1//
2// cpp/gen/command_gen.cpp
3// Generated by AMC
4//
5// Copyright (C) 2008-2013 AlgoEngineering LLC
6// Copyright (C) 2013-2019 NYSE | Intercontinental Exchange
7// Copyright (C) 2020-2023 Astra
8// Copyright (C) 2023 AlgoRND
9//
10// This program is free software: you can redistribute it and/or modify
11// it under the terms of the GNU General Public License as published by
12// the Free Software Foundation, either version 3 of the License, or
13// (at your option) any later version.
14//
15// This program is distributed in the hope that it will be useful,
16// but WITHOUT ANY WARRANTY; without even the implied warranty of
17// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18// GNU General Public License for more details.
19//
20// You should have received a copy of the GNU General Public License
21// along with this program. If not, see <https://www.gnu.org/licenses/>.
22//
23
24
25#include "include/algo.h" // hard-coded include
26#include "include/gen/command_gen.h"
27#include "include/gen/command_gen.inl.h"
28#include "include/gen/algo_lib_gen.h"
29#include "include/gen/algo_lib_gen.inl.h"
30#include "include/gen/algo_gen.h"
31#include "include/gen/algo_gen.inl.h"
32#include "include/gen/ietf_gen.h"
33#include "include/gen/ietf_gen.inl.h"
34//#pragma endinclude
35namespace command { // gen:ns_print_proto
36 // func:command...SizeCheck
37 static void SizeCheck();
38} // gen:ns_print_proto
39
40// --- command.FieldId.value.ToCstr
41// Convert numeric value of field to one of predefined string constants.
42// If string is found, return a static C string. Otherwise, return NULL.
43const char* command::value_ToCstr(const command::FieldId& parent) {
44 const char *ret = NULL;
45 switch(value_GetEnum(parent)) {
46 case command_FieldId_target : ret = "target"; break;
47 case command_FieldId_in : ret = "in"; break;
48 case command_FieldId_out_dir : ret = "out_dir"; break;
49 case command_FieldId_cfg : ret = "cfg"; break;
50 case command_FieldId_compiler : ret = "compiler"; break;
51 case command_FieldId_uname : ret = "uname"; break;
52 case command_FieldId_arch : ret = "arch"; break;
53 case command_FieldId_ood : ret = "ood"; break;
54 case command_FieldId_list : ret = "list"; break;
55 case command_FieldId_listincl : ret = "listincl"; break;
56 case command_FieldId_build : ret = "build"; break;
57 case command_FieldId_preproc : ret = "preproc"; break;
58 case command_FieldId_clean : ret = "clean"; break;
59 case command_FieldId_dry_run : ret = "dry_run"; break;
60 case command_FieldId_maxjobs : ret = "maxjobs"; break;
61 case command_FieldId_printcmd : ret = "printcmd"; break;
62 case command_FieldId_force : ret = "force"; break;
63 case command_FieldId_install : ret = "install"; break;
64 case command_FieldId_coverity : ret = "coverity"; break;
65 case command_FieldId_package : ret = "package"; break;
66 case command_FieldId_maxerr : ret = "maxerr"; break;
67 case command_FieldId_disas : ret = "disas"; break;
68 case command_FieldId_report : ret = "report"; break;
69 case command_FieldId_jcdb : ret = "jcdb"; break;
70 case command_FieldId_cache : ret = "cache"; break;
71 case command_FieldId_readme : ret = "readme"; break;
72 case command_FieldId_ns : ret = "ns"; break;
73 case command_FieldId_section : ret = "section"; break;
74 case command_FieldId_update : ret = "update"; break;
75 case command_FieldId_check : ret = "check"; break;
76 case command_FieldId_link : ret = "link"; break;
77 case command_FieldId_anchor : ret = "anchor"; break;
78 case command_FieldId_print : ret = "print"; break;
79 case command_FieldId_query : ret = "query"; break;
80 case command_FieldId_where : ret = "where"; break;
81 case command_FieldId_del : ret = "del"; break;
82 case command_FieldId_sel : ret = "sel"; break;
83 case command_FieldId_insert : ret = "insert"; break;
84 case command_FieldId_replace : ret = "replace"; break;
85 case command_FieldId_merge : ret = "merge"; break;
86 case command_FieldId_unused : ret = "unused"; break;
87 case command_FieldId_trunc : ret = "trunc"; break;
88 case command_FieldId_selerr : ret = "selerr"; break;
89 case command_FieldId_maxshow : ret = "maxshow"; break;
90 case command_FieldId_write : ret = "write"; break;
91 case command_FieldId_rename : ret = "rename"; break;
92 case command_FieldId_nup : ret = "nup"; break;
93 case command_FieldId_ndown : ret = "ndown"; break;
94 case command_FieldId_l : ret = "l"; break;
95 case command_FieldId_xref : ret = "xref"; break;
96 case command_FieldId_fldfunc : ret = "fldfunc"; break;
97 case command_FieldId_maxgroup : ret = "maxgroup"; break;
98 case command_FieldId_pretty : ret = "pretty"; break;
99 case command_FieldId_tree : ret = "tree"; break;
100 case command_FieldId_loose : ret = "loose"; break;
101 case command_FieldId_my : ret = "my"; break;
102 case command_FieldId_schema : ret = "schema"; break;
103 case command_FieldId_e : ret = "e"; break;
104 case command_FieldId_t : ret = "t"; break;
105 case command_FieldId_g : ret = "g"; break;
106 case command_FieldId_x : ret = "x"; break;
107 case command_FieldId_rowid : ret = "rowid"; break;
108 case command_FieldId_cmt : ret = "cmt"; break;
109 case command_FieldId_cmd : ret = "cmd"; break;
110 case command_FieldId_field : ret = "field"; break;
111 case command_FieldId_regxof : ret = "regxof"; break;
112 case command_FieldId_meta : ret = "meta"; break;
113 case command_FieldId_data : ret = "data"; break;
114 case command_FieldId_line : ret = "line"; break;
115 case command_FieldId_point : ret = "point"; break;
116 case command_FieldId_type : ret = "type"; break;
117 case command_FieldId_debug_log : ret = "debug_log"; break;
118 case command_FieldId_arg : ret = "arg"; break;
119 case command_FieldId_write_ours : ret = "write_ours"; break;
120 case command_FieldId_msize : ret = "msize"; break;
121 case command_FieldId_create : ret = "create"; break;
122 case command_FieldId_finput : ret = "finput"; break;
123 case command_FieldId_foutput : ret = "foutput"; break;
124 case command_FieldId_srcfile : ret = "srcfile"; break;
125 case command_FieldId_gstatic : ret = "gstatic"; break;
126 case command_FieldId_indexed : ret = "indexed"; break;
127 case command_FieldId_nstype : ret = "nstype"; break;
128 case command_FieldId_ctype : ret = "ctype"; break;
129 case command_FieldId_pooltype : ret = "pooltype"; break;
130 case command_FieldId_ssimfile : ret = "ssimfile"; break;
131 case command_FieldId_subset : ret = "subset"; break;
132 case command_FieldId_subset2 : ret = "subset2"; break;
133 case command_FieldId_separator : ret = "separator"; break;
134 case command_FieldId_dflt : ret = "dflt"; break;
135 case command_FieldId_anon : ret = "anon"; break;
136 case command_FieldId_bigend : ret = "bigend"; break;
137 case command_FieldId_cascdel : ret = "cascdel"; break;
138 case command_FieldId_before : ret = "before"; break;
139 case command_FieldId_substr : ret = "substr"; break;
140 case command_FieldId_alias : ret = "alias"; break;
141 case command_FieldId_srcfield : ret = "srcfield"; break;
142 case command_FieldId_fstep : ret = "fstep"; break;
143 case command_FieldId_inscond : ret = "inscond"; break;
144 case command_FieldId_reftype : ret = "reftype"; break;
145 case command_FieldId_hashfld : ret = "hashfld"; break;
146 case command_FieldId_sortfld : ret = "sortfld"; break;
147 case command_FieldId_unittest : ret = "unittest"; break;
148 case command_FieldId_citest : ret = "citest"; break;
149 case command_FieldId_cppfunc : ret = "cppfunc"; break;
150 case command_FieldId_via : ret = "via"; break;
151 case command_FieldId_comment : ret = "comment"; break;
152 case command_FieldId_sandbox : ret = "sandbox"; break;
153 case command_FieldId_test : ret = "test"; break;
154 case command_FieldId_showcpp : ret = "showcpp"; break;
155 case command_FieldId_msgtype : ret = "msgtype"; break;
156 case command_FieldId_anonfld : ret = "anonfld"; break;
157 case command_FieldId_sigcheck : ret = "sigcheck"; break;
158 case command_FieldId_data_dir : ret = "data_dir"; break;
159 case command_FieldId_related : ret = "related"; break;
160 case command_FieldId_notssimfile : ret = "notssimfile"; break;
161 case command_FieldId_checkable : ret = "checkable"; break;
162 case command_FieldId_r : ret = "r"; break;
163 case command_FieldId_nsdb : ret = "nsdb"; break;
164 case command_FieldId_fkey : ret = "fkey"; break;
165 case command_FieldId_start : ret = "start"; break;
166 case command_FieldId_stop : ret = "stop"; break;
167 case command_FieldId_abort : ret = "abort"; break;
168 case command_FieldId_shell : ret = "shell"; break;
169 case command_FieldId_serv : ret = "serv"; break;
170 case command_FieldId_in_dir : ret = "in_dir"; break;
171 case command_FieldId_proto : ret = "proto"; break;
172 case command_FieldId_trace : ret = "trace"; break;
173 case command_FieldId_key : ret = "key"; break;
174 case command_FieldId_include : ret = "include"; break;
175 case command_FieldId_dot : ret = "dot"; break;
176 case command_FieldId_xns : ret = "xns"; break;
177 case command_FieldId_noinput : ret = "noinput"; break;
178 case command_FieldId_render : ret = "render"; break;
179 case command_FieldId_id : ret = "id"; break;
180 case command_FieldId_file_prefix : ret = "file_prefix"; break;
181 case command_FieldId_nchild : ret = "nchild"; break;
182 case command_FieldId_blocking : ret = "blocking"; break;
183 case command_FieldId_nmsg : ret = "nmsg"; break;
184 case command_FieldId_timeout : ret = "timeout"; break;
185 case command_FieldId_recvdelay_ns : ret = "recvdelay_ns"; break;
186 case command_FieldId_senddelay_ns : ret = "senddelay_ns"; break;
187 case command_FieldId_msgsize_min : ret = "msgsize_min"; break;
188 case command_FieldId_msgsize_max : ret = "msgsize_max"; break;
189 case command_FieldId_bufsize : ret = "bufsize"; break;
190 case command_FieldId_recvdelay : ret = "recvdelay"; break;
191 case command_FieldId_pkgdata : ret = "pkgdata"; break;
192 case command_FieldId_diff : ret = "diff"; break;
193 case command_FieldId_push : ret = "push"; break;
194 case command_FieldId_remove : ret = "remove"; break;
195 case command_FieldId_origin : ret = "origin"; break;
196 case command_FieldId_ref : ret = "ref"; break;
197 case command_FieldId_showrec : ret = "showrec"; break;
198 case command_FieldId_showfile : ret = "showfile"; break;
199 case command_FieldId_R : ret = "R"; break;
200 case command_FieldId_reset : ret = "reset"; break;
201 case command_FieldId_checkclean : ret = "checkclean"; break;
202 case command_FieldId_stat : ret = "stat"; break;
203 case command_FieldId_annotate : ret = "annotate"; break;
204 case command_FieldId_data_in : ret = "data_in"; break;
205 case command_FieldId_binpath : ret = "binpath"; break;
206 case command_FieldId_amctest : ret = "amctest"; break;
207 case command_FieldId_dofork : ret = "dofork"; break;
208 case command_FieldId_q : ret = "q"; break;
209 case command_FieldId_cijob : ret = "cijob"; break;
210 case command_FieldId_capture : ret = "capture"; break;
211 case command_FieldId_exec : ret = "exec"; break;
212 case command_FieldId_astr : ret = "astr"; break;
213 case command_FieldId_anum : ret = "anum"; break;
214 case command_FieldId_adbl : ret = "adbl"; break;
215 case command_FieldId_aflag : ret = "aflag"; break;
216 case command_FieldId_str : ret = "str"; break;
217 case command_FieldId_num : ret = "num"; break;
218 case command_FieldId_dbl : ret = "dbl"; break;
219 case command_FieldId_flag : ret = "flag"; break;
220 case command_FieldId_dstr : ret = "dstr"; break;
221 case command_FieldId_dnum : ret = "dnum"; break;
222 case command_FieldId_ddbl : ret = "ddbl"; break;
223 case command_FieldId_dflag : ret = "dflag"; break;
224 case command_FieldId_mstr : ret = "mstr"; break;
225 case command_FieldId_mnum : ret = "mnum"; break;
226 case command_FieldId_mdbl : ret = "mdbl"; break;
227 case command_FieldId_amnum : ret = "amnum"; break;
228 case command_FieldId_fconst : ret = "fconst"; break;
229 case command_FieldId_cconst : ret = "cconst"; break;
230 case command_FieldId_dregx : ret = "dregx"; break;
231 case command_FieldId_dpkey : ret = "dpkey"; break;
232 case command_FieldId_comptest : ret = "comptest"; break;
233 case command_FieldId_mdbg : ret = "mdbg"; break;
234 case command_FieldId_run : ret = "run"; break;
235 case command_FieldId_printinput : ret = "printinput"; break;
236 case command_FieldId_normalize : ret = "normalize"; break;
237 case command_FieldId_covcapture : ret = "covcapture"; break;
238 case command_FieldId_covcheck : ret = "covcheck"; break;
239 case command_FieldId_compdir : ret = "compdir"; break;
240 case command_FieldId_check_untracked: ret = "check_untracked"; break;
241 case command_FieldId_memcheck : ret = "memcheck"; break;
242 case command_FieldId_callgrind : ret = "callgrind"; break;
243 case command_FieldId_stream : ret = "stream"; break;
244 case command_FieldId_i : ret = "i"; break;
245 case command_FieldId_b : ret = "b"; break;
246 case command_FieldId_covdir : ret = "covdir"; break;
247 case command_FieldId_logfile : ret = "logfile"; break;
248 case command_FieldId_runcmd : ret = "runcmd"; break;
249 case command_FieldId_exclude : ret = "exclude"; break;
250 case command_FieldId_mergepath : ret = "mergepath"; break;
251 case command_FieldId_gcov : ret = "gcov"; break;
252 case command_FieldId_ssim : ret = "ssim"; break;
253 case command_FieldId_xmlpretty : ret = "xmlpretty"; break;
254 case command_FieldId_summary : ret = "summary"; break;
255 case command_FieldId_reprofile : ret = "reprofile"; break;
256 case command_FieldId_args : ret = "args"; break;
257 case command_FieldId_inputfile : ret = "inputfile"; break;
258 case command_FieldId_fuzzstrat : ret = "fuzzstrat"; break;
259 case command_FieldId_seed : ret = "seed"; break;
260 case command_FieldId_testprob : ret = "testprob"; break;
261 case command_FieldId_gtblacttst : ret = "gtblacttst"; break;
262 case command_FieldId_mr : ret = "mr"; break;
263 case command_FieldId_note : ret = "note"; break;
264 case command_FieldId_skip_init : ret = "skip_init"; break;
265 case command_FieldId_skip_git_init : ret = "skip_git_init"; break;
266 case command_FieldId_randomize_ports: ret = "randomize_ports"; break;
267 case command_FieldId_ncmd : ret = "ncmd"; break;
268 case command_FieldId_nofork : ret = "nofork"; break;
269 case command_FieldId_perf_secs : ret = "perf_secs"; break;
270 case command_FieldId_pertest_timeout: ret = "pertest_timeout"; break;
271 case command_FieldId_wtblacttst : ret = "wtblacttst"; break;
272 case command_FieldId_wiki_envnode : ret = "wiki_envnode"; break;
273 case command_FieldId_wiki_kill : ret = "wiki_kill"; break;
274 case command_FieldId_wiki_start : ret = "wiki_start"; break;
275 case command_FieldId_wiki_update : ret = "wiki_update"; break;
276 case command_FieldId_wiki_update_help: ret = "wiki_update_help"; break;
277 case command_FieldId_wiki_update_fields: ret = "wiki_update_fields"; break;
278 case command_FieldId_wiki_clean_start: ret = "wiki_clean_start"; break;
279 case command_FieldId_authdir_dflt : ret = "authdir_dflt"; break;
280 case command_FieldId_wikisite : ret = "wikisite"; break;
281 case command_FieldId_cmd_dctr : ret = "cmd_dctr"; break;
282 case command_FieldId_config_ssh : ret = "config_ssh"; break;
283 case command_FieldId_config_ssh_vpn: ret = "config_ssh_vpn"; break;
284 case command_FieldId_clean_run : ret = "clean_run"; break;
285 case command_FieldId_inspect : ret = "inspect"; break;
286 case command_FieldId_logs : ret = "logs"; break;
287 case command_FieldId_generate_build: ret = "generate_build"; break;
288 case command_FieldId_dhost : ret = "dhost"; break;
289 case command_FieldId_dctr : ret = "dctr"; break;
290 case command_FieldId_dctrhost : ret = "dctrhost"; break;
291 case command_FieldId_script_dir : ret = "script_dir"; break;
292 case command_FieldId_cloneto : ret = "cloneto"; break;
293 case command_FieldId_renameto : ret = "renameto"; break;
294 case command_FieldId_purge : ret = "purge"; break;
295 case command_FieldId_deep : ret = "deep"; break;
296 case command_FieldId_sync : ret = "sync"; break;
297 case command_FieldId_keep_files : ret = "keep_files"; break;
298 case command_FieldId_dctr_from : ret = "dctr_from"; break;
299 case command_FieldId_dhost_ip : ret = "dhost_ip"; break;
300 case command_FieldId_dhost_ext_ip : ret = "dhost_ext_ip"; break;
301 case command_FieldId_dhost_ext_port: ret = "dhost_ext_port"; break;
302 case command_FieldId_dhost_user : ret = "dhost_user"; break;
303 case command_FieldId_genamc : ret = "genamc"; break;
304 case command_FieldId_xml : ret = "xml"; break;
305 case command_FieldId_add_reset : ret = "add_reset"; break;
306 case command_FieldId_encode : ret = "encode"; break;
307 case command_FieldId_decode : ret = "decode"; break;
308 case command_FieldId_enc : ret = "enc"; break;
309 case command_FieldId_nullable : ret = "nullable"; break;
310 case command_FieldId_ifmt : ret = "ifmt"; break;
311 case command_FieldId_ofmt : ret = "ofmt"; break;
312 case command_FieldId_echo : ret = "echo"; break;
313 case command_FieldId_hex : ret = "hex"; break;
314 case command_FieldId_fix_bs : ret = "fix_bs"; break;
315 case command_FieldId_fix_soh : ret = "fix_soh"; break;
316 case command_FieldId_fix_nl : ret = "fix_nl"; break;
317 case command_FieldId_fast_msg_max : ret = "fast_msg_max"; break;
318 case command_FieldId_stats : ret = "stats"; break;
319 case command_FieldId_enable : ret = "enable"; break;
320 case command_FieldId_disable : ret = "disable"; break;
321 case command_FieldId_gc : ret = "gc"; break;
322 case command_FieldId_dir : ret = "dir"; break;
323 case command_FieldId_hitrate : ret = "hitrate"; break;
324 case command_FieldId_after : ret = "after"; break;
325 case command_FieldId_selector : ret = "selector"; break;
326 case command_FieldId_fields : ret = "fields"; break;
327 case command_FieldId_accept : ret = "accept"; break;
328 case command_FieldId_approve : ret = "approve"; break;
329 case command_FieldId_needs_work : ret = "needs_work"; break;
330 case command_FieldId_authdir : ret = "authdir"; break;
331 case command_FieldId_gitdir : ret = "gitdir"; break;
332 case command_FieldId_show_gitlab_system_notes: ret = "show_gitlab_system_notes"; break;
333 case command_FieldId_gmvproj : ret = "gmvproj"; break;
334 case command_FieldId_move_out : ret = "move_out"; break;
335 case command_FieldId_move_in : ret = "move_in"; break;
336 case command_FieldId_commit : ret = "commit"; break;
337 case command_FieldId_no_rebase : ret = "no_rebase"; break;
338 case command_FieldId_attach : ret = "attach"; break;
339 case command_FieldId_catchthrow : ret = "catchthrow"; break;
340 case command_FieldId_tui : ret = "tui"; break;
341 case command_FieldId_bcmd : ret = "bcmd"; break;
342 case command_FieldId_emacs : ret = "emacs"; break;
343 case command_FieldId_manywin : ret = "manywin"; break;
344 case command_FieldId_follow_child : ret = "follow_child"; break;
345 case command_FieldId_py : ret = "py"; break;
346 case command_FieldId_writessimfile : ret = "writessimfile"; break;
347 case command_FieldId_url : ret = "url"; break;
348 case command_FieldId_tables : ret = "tables"; break;
349 case command_FieldId_nologo : ret = "nologo"; break;
350 case command_FieldId_baddbok : ret = "baddbok"; break;
351 case command_FieldId_move : ret = "move"; break;
352 case command_FieldId_dedup : ret = "dedup"; break;
353 case command_FieldId_undo : ret = "undo"; break;
354 case command_FieldId_hash : ret = "hash"; break;
355 case command_FieldId_expr : ret = "expr"; break;
356 case command_FieldId_style : ret = "style"; break;
357 case command_FieldId_match : ret = "match"; break;
358 case command_FieldId_string : ret = "string"; break;
359 case command_FieldId_show : ret = "show"; break;
360 case command_FieldId_name : ret = "name"; break;
361 case command_FieldId_files : ret = "files"; break;
362 case command_FieldId_refs : ret = "refs"; break;
363 case command_FieldId_site : ret = "site"; break;
364 case command_FieldId_builder : ret = "builder"; break;
365 case command_FieldId_build_fail_on_warning: ret = "build_fail_on_warning"; break;
366 case command_FieldId_build_quiet : ret = "build_quiet"; break;
367 case command_FieldId_jobs : ret = "jobs"; break;
368 case command_FieldId_preserve_footer: ret = "preserve_footer"; break;
369 case command_FieldId_serve : ret = "serve"; break;
370 case command_FieldId_serve_dctrhost: ret = "serve_dctrhost"; break;
371 case command_FieldId_serve_pages : ret = "serve_pages"; break;
372 case command_FieldId_serve_verify : ret = "serve_verify"; break;
373 case command_FieldId_workdir : ret = "workdir"; break;
374 case command_FieldId_opts_numbered : ret = "opts_numbered"; break;
375 case command_FieldId_body : ret = "body"; break;
376 case command_FieldId_targsrc : ret = "targsrc"; break;
377 case command_FieldId_func : ret = "func"; break;
378 case command_FieldId_nextfile : ret = "nextfile"; break;
379 case command_FieldId_other : ret = "other"; break;
380 case command_FieldId_updateproto : ret = "updateproto"; break;
381 case command_FieldId_listfunc : ret = "listfunc"; break;
382 case command_FieldId_iffy : ret = "iffy"; break;
383 case command_FieldId_gen : ret = "gen"; break;
384 case command_FieldId_showloc : ret = "showloc"; break;
385 case command_FieldId_showstatic : ret = "showstatic"; break;
386 case command_FieldId_showsortkey : ret = "showsortkey"; break;
387 case command_FieldId_sortname : ret = "sortname"; break;
388 case command_FieldId_baddecl : ret = "baddecl"; break;
389 case command_FieldId_indent : ret = "indent"; break;
390 case command_FieldId_update_copyright: ret = "update_copyright"; break;
391 case command_FieldId_scriptfile : ret = "scriptfile"; break;
392 case command_FieldId_linelim : ret = "linelim"; break;
393 case command_FieldId_strayfile : ret = "strayfile"; break;
394 case command_FieldId_badchar : ret = "badchar"; break;
395 case command_FieldId_badline : ret = "badline"; break;
396 case command_FieldId_expand : ret = "expand"; break;
397 case command_FieldId_ignoreQuote : ret = "ignoreQuote"; break;
398 case command_FieldId_maxpacket : ret = "maxpacket"; break;
399 case command_FieldId_db : ret = "db"; break;
400 case command_FieldId_createdb : ret = "createdb"; break;
401 case command_FieldId_typetag : ret = "typetag"; break;
402 case command_FieldId_format : ret = "format"; break;
403 case command_FieldId_tocamelcase : ret = "tocamelcase"; break;
404 case command_FieldId_tolowerunder : ret = "tolowerunder"; break;
405 case command_FieldId_pathcomp : ret = "pathcomp"; break;
406 case command_FieldId_fname : ret = "fname"; break;
407 case command_FieldId_outseparator : ret = "outseparator"; break;
408 case command_FieldId_header : ret = "header"; break;
409 case command_FieldId_prefer_signed : ret = "prefer_signed"; break;
410 case command_FieldId_begin : ret = "begin"; break;
411 case command_FieldId_end : ret = "end"; break;
412 case command_FieldId_stay : ret = "stay"; break;
413 case command_FieldId_from : ret = "from"; break;
414 case command_FieldId_to : ret = "to"; break;
415 case command_FieldId_download : ret = "download"; break;
416 case command_FieldId_upload : ret = "upload"; break;
417 case command_FieldId_ignore_saved_edit: ret = "ignore_saved_edit"; break;
418 case command_FieldId_exclude_subpages: ret = "exclude_subpages"; break;
419 case command_FieldId_pagedir : ret = "pagedir"; break;
420 case command_FieldId_envnode : ret = "envnode"; break;
421 case command_FieldId_admsvc : ret = "admsvc"; break;
422 case command_FieldId_generate : ret = "generate"; break;
423 case command_FieldId_verify : ret = "verify"; break;
424 case command_FieldId_prefix : ret = "prefix"; break;
425 case command_FieldId_root : ret = "root"; break;
426 case command_FieldId_user : ret = "user"; break;
427 case command_FieldId_rsync_put : ret = "rsync_put"; break;
428 case command_FieldId_rsync_get : ret = "rsync_get"; break;
429 case command_FieldId_rsync_opts : ret = "rsync_opts"; break;
430 case command_FieldId_local : ret = "local"; break;
431 case command_FieldId_remote : ret = "remote"; break;
432 case command_FieldId_maxtime : ret = "maxtime"; break;
433 case command_FieldId_gw : ret = "gw"; break;
434 case command_FieldId_value : ret = "value"; break;
435 }
436 return ret;
437}
438
439// --- command.FieldId.value.Print
440// Convert value to a string. First, attempt conversion to a known string.
441// If no string matches, print value as a numeric value.
442void command::value_Print(const command::FieldId& parent, algo::cstring &lhs) {
443 const char *strval = value_ToCstr(parent);
444 if (strval) {
445 lhs << strval;
446 } else {
447 lhs << parent.value;
448 }
449}
450
451// --- command.FieldId.value.SetStrptrMaybe
452// Convert string to field.
453// If the string is invalid, do not modify field and return false.
454// In case of success, return true
455bool command::value_SetStrptrMaybe(command::FieldId& parent, algo::strptr rhs) {
456 bool ret = false;
457 switch (elems_N(rhs)) {
458 case 1: {
459 switch (u64(rhs[0])) {
460 case 'R': {
461 value_SetEnum(parent,command_FieldId_R); ret = true; break;
462 }
463 case 'b': {
464 value_SetEnum(parent,command_FieldId_b); ret = true; break;
465 }
466 case 'e': {
467 value_SetEnum(parent,command_FieldId_e); ret = true; break;
468 }
469 case 'g': {
470 value_SetEnum(parent,command_FieldId_g); ret = true; break;
471 }
472 case 'i': {
473 value_SetEnum(parent,command_FieldId_i); ret = true; break;
474 }
475 case 'l': {
476 value_SetEnum(parent,command_FieldId_l); ret = true; break;
477 }
478 case 'q': {
479 value_SetEnum(parent,command_FieldId_q); ret = true; break;
480 }
481 case 'r': {
482 value_SetEnum(parent,command_FieldId_r); ret = true; break;
483 }
484 case 't': {
485 value_SetEnum(parent,command_FieldId_t); ret = true; break;
486 }
487 case 'x': {
488 value_SetEnum(parent,command_FieldId_x); ret = true; break;
489 }
490 }
491 break;
492 }
493 case 2: {
494 switch (u64(algo::ReadLE16(rhs.elems))) {
495 case LE_STR2('d','b'): {
496 value_SetEnum(parent,command_FieldId_db); ret = true; break;
497 }
498 case LE_STR2('g','c'): {
499 value_SetEnum(parent,command_FieldId_gc); ret = true; break;
500 }
501 case LE_STR2('g','w'): {
502 value_SetEnum(parent,command_FieldId_gw); ret = true; break;
503 }
504 case LE_STR2('i','d'): {
505 value_SetEnum(parent,command_FieldId_id); ret = true; break;
506 }
507 case LE_STR2('i','n'): {
508 value_SetEnum(parent,command_FieldId_in); ret = true; break;
509 }
510 case LE_STR2('m','r'): {
511 value_SetEnum(parent,command_FieldId_mr); ret = true; break;
512 }
513 case LE_STR2('m','y'): {
514 value_SetEnum(parent,command_FieldId_my); ret = true; break;
515 }
516 case LE_STR2('n','s'): {
517 value_SetEnum(parent,command_FieldId_ns); ret = true; break;
518 }
519 case LE_STR2('p','y'): {
520 value_SetEnum(parent,command_FieldId_py); ret = true; break;
521 }
522 case LE_STR2('t','o'): {
523 value_SetEnum(parent,command_FieldId_to); ret = true; break;
524 }
525 }
526 break;
527 }
528 case 3: {
529 switch (u64(algo::ReadLE16(rhs.elems))|(u64(rhs[2])<<16)) {
530 case LE_STR3('a','r','g'): {
531 value_SetEnum(parent,command_FieldId_arg); ret = true; break;
532 }
533 case LE_STR3('c','f','g'): {
534 value_SetEnum(parent,command_FieldId_cfg); ret = true; break;
535 }
536 case LE_STR3('c','m','d'): {
537 value_SetEnum(parent,command_FieldId_cmd); ret = true; break;
538 }
539 case LE_STR3('c','m','t'): {
540 value_SetEnum(parent,command_FieldId_cmt); ret = true; break;
541 }
542 case LE_STR3('d','b','l'): {
543 value_SetEnum(parent,command_FieldId_dbl); ret = true; break;
544 }
545 case LE_STR3('d','e','l'): {
546 value_SetEnum(parent,command_FieldId_del); ret = true; break;
547 }
548 case LE_STR3('d','i','r'): {
549 value_SetEnum(parent,command_FieldId_dir); ret = true; break;
550 }
551 case LE_STR3('d','o','t'): {
552 value_SetEnum(parent,command_FieldId_dot); ret = true; break;
553 }
554 case LE_STR3('e','n','c'): {
555 value_SetEnum(parent,command_FieldId_enc); ret = true; break;
556 }
557 case LE_STR3('e','n','d'): {
558 value_SetEnum(parent,command_FieldId_end); ret = true; break;
559 }
560 case LE_STR3('g','e','n'): {
561 value_SetEnum(parent,command_FieldId_gen); ret = true; break;
562 }
563 case LE_STR3('h','e','x'): {
564 value_SetEnum(parent,command_FieldId_hex); ret = true; break;
565 }
566 case LE_STR3('k','e','y'): {
567 value_SetEnum(parent,command_FieldId_key); ret = true; break;
568 }
569 case LE_STR3('n','u','m'): {
570 value_SetEnum(parent,command_FieldId_num); ret = true; break;
571 }
572 case LE_STR3('n','u','p'): {
573 value_SetEnum(parent,command_FieldId_nup); ret = true; break;
574 }
575 case LE_STR3('o','o','d'): {
576 value_SetEnum(parent,command_FieldId_ood); ret = true; break;
577 }
578 case LE_STR3('r','e','f'): {
579 value_SetEnum(parent,command_FieldId_ref); ret = true; break;
580 }
581 case LE_STR3('r','u','n'): {
582 value_SetEnum(parent,command_FieldId_run); ret = true; break;
583 }
584 case LE_STR3('s','e','l'): {
585 value_SetEnum(parent,command_FieldId_sel); ret = true; break;
586 }
587 case LE_STR3('s','t','r'): {
588 value_SetEnum(parent,command_FieldId_str); ret = true; break;
589 }
590 case LE_STR3('t','u','i'): {
591 value_SetEnum(parent,command_FieldId_tui); ret = true; break;
592 }
593 case LE_STR3('u','r','l'): {
594 value_SetEnum(parent,command_FieldId_url); ret = true; break;
595 }
596 case LE_STR3('v','i','a'): {
597 value_SetEnum(parent,command_FieldId_via); ret = true; break;
598 }
599 case LE_STR3('x','m','l'): {
600 value_SetEnum(parent,command_FieldId_xml); ret = true; break;
601 }
602 case LE_STR3('x','n','s'): {
603 value_SetEnum(parent,command_FieldId_xns); ret = true; break;
604 }
605 }
606 break;
607 }
608 case 4: {
609 switch (u64(algo::ReadLE32(rhs.elems))) {
610 case LE_STR4('a','d','b','l'): {
611 value_SetEnum(parent,command_FieldId_adbl); ret = true; break;
612 }
613 case LE_STR4('a','n','o','n'): {
614 value_SetEnum(parent,command_FieldId_anon); ret = true; break;
615 }
616 case LE_STR4('a','n','u','m'): {
617 value_SetEnum(parent,command_FieldId_anum); ret = true; break;
618 }
619 case LE_STR4('a','r','c','h'): {
620 value_SetEnum(parent,command_FieldId_arch); ret = true; break;
621 }
622 case LE_STR4('a','r','g','s'): {
623 value_SetEnum(parent,command_FieldId_args); ret = true; break;
624 }
625 case LE_STR4('a','s','t','r'): {
626 value_SetEnum(parent,command_FieldId_astr); ret = true; break;
627 }
628 case LE_STR4('b','c','m','d'): {
629 value_SetEnum(parent,command_FieldId_bcmd); ret = true; break;
630 }
631 case LE_STR4('b','o','d','y'): {
632 value_SetEnum(parent,command_FieldId_body); ret = true; break;
633 }
634 case LE_STR4('d','a','t','a'): {
635 value_SetEnum(parent,command_FieldId_data); ret = true; break;
636 }
637 case LE_STR4('d','c','t','r'): {
638 value_SetEnum(parent,command_FieldId_dctr); ret = true; break;
639 }
640 case LE_STR4('d','d','b','l'): {
641 value_SetEnum(parent,command_FieldId_ddbl); ret = true; break;
642 }
643 case LE_STR4('d','e','e','p'): {
644 value_SetEnum(parent,command_FieldId_deep); ret = true; break;
645 }
646 case LE_STR4('d','f','l','t'): {
647 value_SetEnum(parent,command_FieldId_dflt); ret = true; break;
648 }
649 case LE_STR4('d','i','f','f'): {
650 value_SetEnum(parent,command_FieldId_diff); ret = true; break;
651 }
652 case LE_STR4('d','n','u','m'): {
653 value_SetEnum(parent,command_FieldId_dnum); ret = true; break;
654 }
655 case LE_STR4('d','s','t','r'): {
656 value_SetEnum(parent,command_FieldId_dstr); ret = true; break;
657 }
658 case LE_STR4('e','c','h','o'): {
659 value_SetEnum(parent,command_FieldId_echo); ret = true; break;
660 }
661 case LE_STR4('e','x','e','c'): {
662 value_SetEnum(parent,command_FieldId_exec); ret = true; break;
663 }
664 case LE_STR4('e','x','p','r'): {
665 value_SetEnum(parent,command_FieldId_expr); ret = true; break;
666 }
667 case LE_STR4('f','k','e','y'): {
668 value_SetEnum(parent,command_FieldId_fkey); ret = true; break;
669 }
670 case LE_STR4('f','l','a','g'): {
671 value_SetEnum(parent,command_FieldId_flag); ret = true; break;
672 }
673 case LE_STR4('f','r','o','m'): {
674 value_SetEnum(parent,command_FieldId_from); ret = true; break;
675 }
676 case LE_STR4('f','u','n','c'): {
677 value_SetEnum(parent,command_FieldId_func); ret = true; break;
678 }
679 case LE_STR4('g','c','o','v'): {
680 value_SetEnum(parent,command_FieldId_gcov); ret = true; break;
681 }
682 case LE_STR4('h','a','s','h'): {
683 value_SetEnum(parent,command_FieldId_hash); ret = true; break;
684 }
685 case LE_STR4('i','f','f','y'): {
686 value_SetEnum(parent,command_FieldId_iffy); ret = true; break;
687 }
688 case LE_STR4('i','f','m','t'): {
689 value_SetEnum(parent,command_FieldId_ifmt); ret = true; break;
690 }
691 case LE_STR4('j','c','d','b'): {
692 value_SetEnum(parent,command_FieldId_jcdb); ret = true; break;
693 }
694 case LE_STR4('j','o','b','s'): {
695 value_SetEnum(parent,command_FieldId_jobs); ret = true; break;
696 }
697 case LE_STR4('l','i','n','e'): {
698 value_SetEnum(parent,command_FieldId_line); ret = true; break;
699 }
700 case LE_STR4('l','i','n','k'): {
701 value_SetEnum(parent,command_FieldId_link); ret = true; break;
702 }
703 case LE_STR4('l','i','s','t'): {
704 value_SetEnum(parent,command_FieldId_list); ret = true; break;
705 }
706 case LE_STR4('l','o','g','s'): {
707 value_SetEnum(parent,command_FieldId_logs); ret = true; break;
708 }
709 case LE_STR4('m','d','b','g'): {
710 value_SetEnum(parent,command_FieldId_mdbg); ret = true; break;
711 }
712 case LE_STR4('m','d','b','l'): {
713 value_SetEnum(parent,command_FieldId_mdbl); ret = true; break;
714 }
715 case LE_STR4('m','e','t','a'): {
716 value_SetEnum(parent,command_FieldId_meta); ret = true; break;
717 }
718 case LE_STR4('m','n','u','m'): {
719 value_SetEnum(parent,command_FieldId_mnum); ret = true; break;
720 }
721 case LE_STR4('m','o','v','e'): {
722 value_SetEnum(parent,command_FieldId_move); ret = true; break;
723 }
724 case LE_STR4('m','s','t','r'): {
725 value_SetEnum(parent,command_FieldId_mstr); ret = true; break;
726 }
727 case LE_STR4('n','a','m','e'): {
728 value_SetEnum(parent,command_FieldId_name); ret = true; break;
729 }
730 case LE_STR4('n','c','m','d'): {
731 value_SetEnum(parent,command_FieldId_ncmd); ret = true; break;
732 }
733 case LE_STR4('n','m','s','g'): {
734 value_SetEnum(parent,command_FieldId_nmsg); ret = true; break;
735 }
736 case LE_STR4('n','o','t','e'): {
737 value_SetEnum(parent,command_FieldId_note); ret = true; break;
738 }
739 case LE_STR4('n','s','d','b'): {
740 value_SetEnum(parent,command_FieldId_nsdb); ret = true; break;
741 }
742 case LE_STR4('o','f','m','t'): {
743 value_SetEnum(parent,command_FieldId_ofmt); ret = true; break;
744 }
745 case LE_STR4('p','u','s','h'): {
746 value_SetEnum(parent,command_FieldId_push); ret = true; break;
747 }
748 case LE_STR4('r','e','f','s'): {
749 value_SetEnum(parent,command_FieldId_refs); ret = true; break;
750 }
751 case LE_STR4('r','o','o','t'): {
752 value_SetEnum(parent,command_FieldId_root); ret = true; break;
753 }
754 case LE_STR4('s','e','e','d'): {
755 value_SetEnum(parent,command_FieldId_seed); ret = true; break;
756 }
757 case LE_STR4('s','e','r','v'): {
758 value_SetEnum(parent,command_FieldId_serv); ret = true; break;
759 }
760 case LE_STR4('s','h','o','w'): {
761 value_SetEnum(parent,command_FieldId_show); ret = true; break;
762 }
763 case LE_STR4('s','i','t','e'): {
764 value_SetEnum(parent,command_FieldId_site); ret = true; break;
765 }
766 case LE_STR4('s','s','i','m'): {
767 value_SetEnum(parent,command_FieldId_ssim); ret = true; break;
768 }
769 case LE_STR4('s','t','a','t'): {
770 value_SetEnum(parent,command_FieldId_stat); ret = true; break;
771 }
772 case LE_STR4('s','t','a','y'): {
773 value_SetEnum(parent,command_FieldId_stay); ret = true; break;
774 }
775 case LE_STR4('s','t','o','p'): {
776 value_SetEnum(parent,command_FieldId_stop); ret = true; break;
777 }
778 case LE_STR4('s','y','n','c'): {
779 value_SetEnum(parent,command_FieldId_sync); ret = true; break;
780 }
781 case LE_STR4('t','e','s','t'): {
782 value_SetEnum(parent,command_FieldId_test); ret = true; break;
783 }
784 case LE_STR4('t','r','e','e'): {
785 value_SetEnum(parent,command_FieldId_tree); ret = true; break;
786 }
787 case LE_STR4('t','y','p','e'): {
788 value_SetEnum(parent,command_FieldId_type); ret = true; break;
789 }
790 case LE_STR4('u','n','d','o'): {
791 value_SetEnum(parent,command_FieldId_undo); ret = true; break;
792 }
793 case LE_STR4('u','s','e','r'): {
794 value_SetEnum(parent,command_FieldId_user); ret = true; break;
795 }
796 case LE_STR4('x','r','e','f'): {
797 value_SetEnum(parent,command_FieldId_xref); ret = true; break;
798 }
799 }
800 break;
801 }
802 case 5: {
803 switch (u64(algo::ReadLE32(rhs.elems))|(u64(rhs[4])<<32)) {
804 case LE_STR5('a','b','o','r','t'): {
805 value_SetEnum(parent,command_FieldId_abort); ret = true; break;
806 }
807 case LE_STR5('a','f','l','a','g'): {
808 value_SetEnum(parent,command_FieldId_aflag); ret = true; break;
809 }
810 case LE_STR5('a','f','t','e','r'): {
811 value_SetEnum(parent,command_FieldId_after); ret = true; break;
812 }
813 case LE_STR5('a','l','i','a','s'): {
814 value_SetEnum(parent,command_FieldId_alias); ret = true; break;
815 }
816 case LE_STR5('a','m','n','u','m'): {
817 value_SetEnum(parent,command_FieldId_amnum); ret = true; break;
818 }
819 case LE_STR5('b','e','g','i','n'): {
820 value_SetEnum(parent,command_FieldId_begin); ret = true; break;
821 }
822 case LE_STR5('b','u','i','l','d'): {
823 value_SetEnum(parent,command_FieldId_build); ret = true; break;
824 }
825 case LE_STR5('c','a','c','h','e'): {
826 value_SetEnum(parent,command_FieldId_cache); ret = true; break;
827 }
828 case LE_STR5('c','h','e','c','k'): {
829 value_SetEnum(parent,command_FieldId_check); ret = true; break;
830 }
831 case LE_STR5('c','i','j','o','b'): {
832 value_SetEnum(parent,command_FieldId_cijob); ret = true; break;
833 }
834 case LE_STR5('c','l','e','a','n'): {
835 value_SetEnum(parent,command_FieldId_clean); ret = true; break;
836 }
837 case LE_STR5('c','t','y','p','e'): {
838 value_SetEnum(parent,command_FieldId_ctype); ret = true; break;
839 }
840 case LE_STR5('d','e','d','u','p'): {
841 value_SetEnum(parent,command_FieldId_dedup); ret = true; break;
842 }
843 case LE_STR5('d','f','l','a','g'): {
844 value_SetEnum(parent,command_FieldId_dflag); ret = true; break;
845 }
846 case LE_STR5('d','h','o','s','t'): {
847 value_SetEnum(parent,command_FieldId_dhost); ret = true; break;
848 }
849 case LE_STR5('d','i','s','a','s'): {
850 value_SetEnum(parent,command_FieldId_disas); ret = true; break;
851 }
852 case LE_STR5('d','p','k','e','y'): {
853 value_SetEnum(parent,command_FieldId_dpkey); ret = true; break;
854 }
855 case LE_STR5('d','r','e','g','x'): {
856 value_SetEnum(parent,command_FieldId_dregx); ret = true; break;
857 }
858 case LE_STR5('e','m','a','c','s'): {
859 value_SetEnum(parent,command_FieldId_emacs); ret = true; break;
860 }
861 case LE_STR5('f','i','e','l','d'): {
862 value_SetEnum(parent,command_FieldId_field); ret = true; break;
863 }
864 case LE_STR5('f','i','l','e','s'): {
865 value_SetEnum(parent,command_FieldId_files); ret = true; break;
866 }
867 case LE_STR5('f','n','a','m','e'): {
868 value_SetEnum(parent,command_FieldId_fname); ret = true; break;
869 }
870 case LE_STR5('f','o','r','c','e'): {
871 value_SetEnum(parent,command_FieldId_force); ret = true; break;
872 }
873 case LE_STR5('f','s','t','e','p'): {
874 value_SetEnum(parent,command_FieldId_fstep); ret = true; break;
875 }
876 case LE_STR5('l','o','c','a','l'): {
877 value_SetEnum(parent,command_FieldId_local); ret = true; break;
878 }
879 case LE_STR5('l','o','o','s','e'): {
880 value_SetEnum(parent,command_FieldId_loose); ret = true; break;
881 }
882 case LE_STR5('m','a','t','c','h'): {
883 value_SetEnum(parent,command_FieldId_match); ret = true; break;
884 }
885 case LE_STR5('m','e','r','g','e'): {
886 value_SetEnum(parent,command_FieldId_merge); ret = true; break;
887 }
888 case LE_STR5('m','s','i','z','e'): {
889 value_SetEnum(parent,command_FieldId_msize); ret = true; break;
890 }
891 case LE_STR5('n','d','o','w','n'): {
892 value_SetEnum(parent,command_FieldId_ndown); ret = true; break;
893 }
894 case LE_STR5('o','t','h','e','r'): {
895 value_SetEnum(parent,command_FieldId_other); ret = true; break;
896 }
897 case LE_STR5('p','o','i','n','t'): {
898 value_SetEnum(parent,command_FieldId_point); ret = true; break;
899 }
900 case LE_STR5('p','r','i','n','t'): {
901 value_SetEnum(parent,command_FieldId_print); ret = true; break;
902 }
903 case LE_STR5('p','r','o','t','o'): {
904 value_SetEnum(parent,command_FieldId_proto); ret = true; break;
905 }
906 case LE_STR5('p','u','r','g','e'): {
907 value_SetEnum(parent,command_FieldId_purge); ret = true; break;
908 }
909 case LE_STR5('q','u','e','r','y'): {
910 value_SetEnum(parent,command_FieldId_query); ret = true; break;
911 }
912 case LE_STR5('r','e','s','e','t'): {
913 value_SetEnum(parent,command_FieldId_reset); ret = true; break;
914 }
915 case LE_STR5('r','o','w','i','d'): {
916 value_SetEnum(parent,command_FieldId_rowid); ret = true; break;
917 }
918 case LE_STR5('s','e','r','v','e'): {
919 value_SetEnum(parent,command_FieldId_serve); ret = true; break;
920 }
921 case LE_STR5('s','h','e','l','l'): {
922 value_SetEnum(parent,command_FieldId_shell); ret = true; break;
923 }
924 case LE_STR5('s','t','a','r','t'): {
925 value_SetEnum(parent,command_FieldId_start); ret = true; break;
926 }
927 case LE_STR5('s','t','a','t','s'): {
928 value_SetEnum(parent,command_FieldId_stats); ret = true; break;
929 }
930 case LE_STR5('s','t','y','l','e'): {
931 value_SetEnum(parent,command_FieldId_style); ret = true; break;
932 }
933 case LE_STR5('t','r','a','c','e'): {
934 value_SetEnum(parent,command_FieldId_trace); ret = true; break;
935 }
936 case LE_STR5('t','r','u','n','c'): {
937 value_SetEnum(parent,command_FieldId_trunc); ret = true; break;
938 }
939 case LE_STR5('u','n','a','m','e'): {
940 value_SetEnum(parent,command_FieldId_uname); ret = true; break;
941 }
942 case LE_STR5('v','a','l','u','e'): {
943 value_SetEnum(parent,command_FieldId_value); ret = true; break;
944 }
945 case LE_STR5('w','h','e','r','e'): {
946 value_SetEnum(parent,command_FieldId_where); ret = true; break;
947 }
948 case LE_STR5('w','r','i','t','e'): {
949 value_SetEnum(parent,command_FieldId_write); ret = true; break;
950 }
951 }
952 break;
953 }
954 case 6: {
955 switch (u64(algo::ReadLE32(rhs.elems))|(u64(algo::ReadLE16(rhs.elems+4))<<32)) {
956 case LE_STR6('a','c','c','e','p','t'): {
957 value_SetEnum(parent,command_FieldId_accept); ret = true; break;
958 }
959 case LE_STR6('a','d','m','s','v','c'): {
960 value_SetEnum(parent,command_FieldId_admsvc); ret = true; break;
961 }
962 case LE_STR6('a','n','c','h','o','r'): {
963 value_SetEnum(parent,command_FieldId_anchor); ret = true; break;
964 }
965 case LE_STR6('a','t','t','a','c','h'): {
966 value_SetEnum(parent,command_FieldId_attach); ret = true; break;
967 }
968 case LE_STR6('b','e','f','o','r','e'): {
969 value_SetEnum(parent,command_FieldId_before); ret = true; break;
970 }
971 case LE_STR6('b','i','g','e','n','d'): {
972 value_SetEnum(parent,command_FieldId_bigend); ret = true; break;
973 }
974 case LE_STR6('c','c','o','n','s','t'): {
975 value_SetEnum(parent,command_FieldId_cconst); ret = true; break;
976 }
977 case LE_STR6('c','i','t','e','s','t'): {
978 value_SetEnum(parent,command_FieldId_citest); ret = true; break;
979 }
980 case LE_STR6('c','o','m','m','i','t'): {
981 value_SetEnum(parent,command_FieldId_commit); ret = true; break;
982 }
983 case LE_STR6('c','o','v','d','i','r'): {
984 value_SetEnum(parent,command_FieldId_covdir); ret = true; break;
985 }
986 case LE_STR6('c','r','e','a','t','e'): {
987 value_SetEnum(parent,command_FieldId_create); ret = true; break;
988 }
989 case LE_STR6('d','e','c','o','d','e'): {
990 value_SetEnum(parent,command_FieldId_decode); ret = true; break;
991 }
992 case LE_STR6('d','o','f','o','r','k'): {
993 value_SetEnum(parent,command_FieldId_dofork); ret = true; break;
994 }
995 case LE_STR6('e','n','a','b','l','e'): {
996 value_SetEnum(parent,command_FieldId_enable); ret = true; break;
997 }
998 case LE_STR6('e','n','c','o','d','e'): {
999 value_SetEnum(parent,command_FieldId_encode); ret = true; break;
1000 }
1001 case LE_STR6('e','x','p','a','n','d'): {
1002 value_SetEnum(parent,command_FieldId_expand); ret = true; break;
1003 }
1004 case LE_STR6('f','c','o','n','s','t'): {
1005 value_SetEnum(parent,command_FieldId_fconst); ret = true; break;
1006 }
1007 case LE_STR6('f','i','e','l','d','s'): {
1008 value_SetEnum(parent,command_FieldId_fields); ret = true; break;
1009 }
1010 case LE_STR6('f','i','n','p','u','t'): {
1011 value_SetEnum(parent,command_FieldId_finput); ret = true; break;
1012 }
1013 case LE_STR6('f','i','x','_','b','s'): {
1014 value_SetEnum(parent,command_FieldId_fix_bs); ret = true; break;
1015 }
1016 case LE_STR6('f','i','x','_','n','l'): {
1017 value_SetEnum(parent,command_FieldId_fix_nl); ret = true; break;
1018 }
1019 case LE_STR6('f','o','r','m','a','t'): {
1020 value_SetEnum(parent,command_FieldId_format); ret = true; break;
1021 }
1022 case LE_STR6('g','e','n','a','m','c'): {
1023 value_SetEnum(parent,command_FieldId_genamc); ret = true; break;
1024 }
1025 case LE_STR6('g','i','t','d','i','r'): {
1026 value_SetEnum(parent,command_FieldId_gitdir); ret = true; break;
1027 }
1028 case LE_STR6('h','e','a','d','e','r'): {
1029 value_SetEnum(parent,command_FieldId_header); ret = true; break;
1030 }
1031 case LE_STR6('i','n','_','d','i','r'): {
1032 value_SetEnum(parent,command_FieldId_in_dir); ret = true; break;
1033 }
1034 case LE_STR6('i','n','d','e','n','t'): {
1035 value_SetEnum(parent,command_FieldId_indent); ret = true; break;
1036 }
1037 case LE_STR6('i','n','s','e','r','t'): {
1038 value_SetEnum(parent,command_FieldId_insert); ret = true; break;
1039 }
1040 case LE_STR6('m','a','x','e','r','r'): {
1041 value_SetEnum(parent,command_FieldId_maxerr); ret = true; break;
1042 }
1043 case LE_STR6('n','c','h','i','l','d'): {
1044 value_SetEnum(parent,command_FieldId_nchild); ret = true; break;
1045 }
1046 case LE_STR6('n','o','f','o','r','k'): {
1047 value_SetEnum(parent,command_FieldId_nofork); ret = true; break;
1048 }
1049 case LE_STR6('n','o','l','o','g','o'): {
1050 value_SetEnum(parent,command_FieldId_nologo); ret = true; break;
1051 }
1052 case LE_STR6('n','s','t','y','p','e'): {
1053 value_SetEnum(parent,command_FieldId_nstype); ret = true; break;
1054 }
1055 case LE_STR6('o','r','i','g','i','n'): {
1056 value_SetEnum(parent,command_FieldId_origin); ret = true; break;
1057 }
1058 case LE_STR6('p','r','e','f','i','x'): {
1059 value_SetEnum(parent,command_FieldId_prefix); ret = true; break;
1060 }
1061 case LE_STR6('p','r','e','t','t','y'): {
1062 value_SetEnum(parent,command_FieldId_pretty); ret = true; break;
1063 }
1064 case LE_STR6('r','e','a','d','m','e'): {
1065 value_SetEnum(parent,command_FieldId_readme); ret = true; break;
1066 }
1067 case LE_STR6('r','e','g','x','o','f'): {
1068 value_SetEnum(parent,command_FieldId_regxof); ret = true; break;
1069 }
1070 case LE_STR6('r','e','m','o','t','e'): {
1071 value_SetEnum(parent,command_FieldId_remote); ret = true; break;
1072 }
1073 case LE_STR6('r','e','m','o','v','e'): {
1074 value_SetEnum(parent,command_FieldId_remove); ret = true; break;
1075 }
1076 case LE_STR6('r','e','n','a','m','e'): {
1077 value_SetEnum(parent,command_FieldId_rename); ret = true; break;
1078 }
1079 case LE_STR6('r','e','n','d','e','r'): {
1080 value_SetEnum(parent,command_FieldId_render); ret = true; break;
1081 }
1082 case LE_STR6('r','e','p','o','r','t'): {
1083 value_SetEnum(parent,command_FieldId_report); ret = true; break;
1084 }
1085 case LE_STR6('r','u','n','c','m','d'): {
1086 value_SetEnum(parent,command_FieldId_runcmd); ret = true; break;
1087 }
1088 case LE_STR6('s','c','h','e','m','a'): {
1089 value_SetEnum(parent,command_FieldId_schema); ret = true; break;
1090 }
1091 case LE_STR6('s','e','l','e','r','r'): {
1092 value_SetEnum(parent,command_FieldId_selerr); ret = true; break;
1093 }
1094 case LE_STR6('s','t','r','e','a','m'): {
1095 value_SetEnum(parent,command_FieldId_stream); ret = true; break;
1096 }
1097 case LE_STR6('s','t','r','i','n','g'): {
1098 value_SetEnum(parent,command_FieldId_string); ret = true; break;
1099 }
1100 case LE_STR6('s','u','b','s','e','t'): {
1101 value_SetEnum(parent,command_FieldId_subset); ret = true; break;
1102 }
1103 case LE_STR6('s','u','b','s','t','r'): {
1104 value_SetEnum(parent,command_FieldId_substr); ret = true; break;
1105 }
1106 case LE_STR6('t','a','b','l','e','s'): {
1107 value_SetEnum(parent,command_FieldId_tables); ret = true; break;
1108 }
1109 case LE_STR6('t','a','r','g','e','t'): {
1110 value_SetEnum(parent,command_FieldId_target); ret = true; break;
1111 }
1112 case LE_STR6('u','n','u','s','e','d'): {
1113 value_SetEnum(parent,command_FieldId_unused); ret = true; break;
1114 }
1115 case LE_STR6('u','p','d','a','t','e'): {
1116 value_SetEnum(parent,command_FieldId_update); ret = true; break;
1117 }
1118 case LE_STR6('u','p','l','o','a','d'): {
1119 value_SetEnum(parent,command_FieldId_upload); ret = true; break;
1120 }
1121 case LE_STR6('v','e','r','i','f','y'): {
1122 value_SetEnum(parent,command_FieldId_verify); ret = true; break;
1123 }
1124 }
1125 break;
1126 }
1127 case 7: {
1128 switch (u64(algo::ReadLE32(rhs.elems))|(u64(algo::ReadLE16(rhs.elems+4))<<32)|(u64(rhs[6])<<48)) {
1129 case LE_STR7('a','m','c','t','e','s','t'): {
1130 value_SetEnum(parent,command_FieldId_amctest); ret = true; break;
1131 }
1132 case LE_STR7('a','n','o','n','f','l','d'): {
1133 value_SetEnum(parent,command_FieldId_anonfld); ret = true; break;
1134 }
1135 case LE_STR7('a','p','p','r','o','v','e'): {
1136 value_SetEnum(parent,command_FieldId_approve); ret = true; break;
1137 }
1138 case LE_STR7('a','u','t','h','d','i','r'): {
1139 value_SetEnum(parent,command_FieldId_authdir); ret = true; break;
1140 }
1141 case LE_STR7('b','a','d','c','h','a','r'): {
1142 value_SetEnum(parent,command_FieldId_badchar); ret = true; break;
1143 }
1144 case LE_STR7('b','a','d','d','b','o','k'): {
1145 value_SetEnum(parent,command_FieldId_baddbok); ret = true; break;
1146 }
1147 case LE_STR7('b','a','d','d','e','c','l'): {
1148 value_SetEnum(parent,command_FieldId_baddecl); ret = true; break;
1149 }
1150 case LE_STR7('b','a','d','l','i','n','e'): {
1151 value_SetEnum(parent,command_FieldId_badline); ret = true; break;
1152 }
1153 case LE_STR7('b','i','n','p','a','t','h'): {
1154 value_SetEnum(parent,command_FieldId_binpath); ret = true; break;
1155 }
1156 case LE_STR7('b','u','f','s','i','z','e'): {
1157 value_SetEnum(parent,command_FieldId_bufsize); ret = true; break;
1158 }
1159 case LE_STR7('b','u','i','l','d','e','r'): {
1160 value_SetEnum(parent,command_FieldId_builder); ret = true; break;
1161 }
1162 case LE_STR7('c','a','p','t','u','r','e'): {
1163 value_SetEnum(parent,command_FieldId_capture); ret = true; break;
1164 }
1165 case LE_STR7('c','a','s','c','d','e','l'): {
1166 value_SetEnum(parent,command_FieldId_cascdel); ret = true; break;
1167 }
1168 case LE_STR7('c','l','o','n','e','t','o'): {
1169 value_SetEnum(parent,command_FieldId_cloneto); ret = true; break;
1170 }
1171 case LE_STR7('c','o','m','m','e','n','t'): {
1172 value_SetEnum(parent,command_FieldId_comment); ret = true; break;
1173 }
1174 case LE_STR7('c','o','m','p','d','i','r'): {
1175 value_SetEnum(parent,command_FieldId_compdir); ret = true; break;
1176 }
1177 case LE_STR7('c','p','p','f','u','n','c'): {
1178 value_SetEnum(parent,command_FieldId_cppfunc); ret = true; break;
1179 }
1180 case LE_STR7('d','a','t','a','_','i','n'): {
1181 value_SetEnum(parent,command_FieldId_data_in); ret = true; break;
1182 }
1183 case LE_STR7('d','i','s','a','b','l','e'): {
1184 value_SetEnum(parent,command_FieldId_disable); ret = true; break;
1185 }
1186 case LE_STR7('d','r','y','_','r','u','n'): {
1187 value_SetEnum(parent,command_FieldId_dry_run); ret = true; break;
1188 }
1189 case LE_STR7('e','n','v','n','o','d','e'): {
1190 value_SetEnum(parent,command_FieldId_envnode); ret = true; break;
1191 }
1192 case LE_STR7('e','x','c','l','u','d','e'): {
1193 value_SetEnum(parent,command_FieldId_exclude); ret = true; break;
1194 }
1195 case LE_STR7('f','i','x','_','s','o','h'): {
1196 value_SetEnum(parent,command_FieldId_fix_soh); ret = true; break;
1197 }
1198 case LE_STR7('f','l','d','f','u','n','c'): {
1199 value_SetEnum(parent,command_FieldId_fldfunc); ret = true; break;
1200 }
1201 case LE_STR7('f','o','u','t','p','u','t'): {
1202 value_SetEnum(parent,command_FieldId_foutput); ret = true; break;
1203 }
1204 case LE_STR7('g','m','v','p','r','o','j'): {
1205 value_SetEnum(parent,command_FieldId_gmvproj); ret = true; break;
1206 }
1207 case LE_STR7('g','s','t','a','t','i','c'): {
1208 value_SetEnum(parent,command_FieldId_gstatic); ret = true; break;
1209 }
1210 case LE_STR7('h','a','s','h','f','l','d'): {
1211 value_SetEnum(parent,command_FieldId_hashfld); ret = true; break;
1212 }
1213 case LE_STR7('h','i','t','r','a','t','e'): {
1214 value_SetEnum(parent,command_FieldId_hitrate); ret = true; break;
1215 }
1216 case LE_STR7('i','n','c','l','u','d','e'): {
1217 value_SetEnum(parent,command_FieldId_include); ret = true; break;
1218 }
1219 case LE_STR7('i','n','d','e','x','e','d'): {
1220 value_SetEnum(parent,command_FieldId_indexed); ret = true; break;
1221 }
1222 case LE_STR7('i','n','s','c','o','n','d'): {
1223 value_SetEnum(parent,command_FieldId_inscond); ret = true; break;
1224 }
1225 case LE_STR7('i','n','s','p','e','c','t'): {
1226 value_SetEnum(parent,command_FieldId_inspect); ret = true; break;
1227 }
1228 case LE_STR7('i','n','s','t','a','l','l'): {
1229 value_SetEnum(parent,command_FieldId_install); ret = true; break;
1230 }
1231 case LE_STR7('l','i','n','e','l','i','m'): {
1232 value_SetEnum(parent,command_FieldId_linelim); ret = true; break;
1233 }
1234 case LE_STR7('l','o','g','f','i','l','e'): {
1235 value_SetEnum(parent,command_FieldId_logfile); ret = true; break;
1236 }
1237 case LE_STR7('m','a','n','y','w','i','n'): {
1238 value_SetEnum(parent,command_FieldId_manywin); ret = true; break;
1239 }
1240 case LE_STR7('m','a','x','j','o','b','s'): {
1241 value_SetEnum(parent,command_FieldId_maxjobs); ret = true; break;
1242 }
1243 case LE_STR7('m','a','x','s','h','o','w'): {
1244 value_SetEnum(parent,command_FieldId_maxshow); ret = true; break;
1245 }
1246 case LE_STR7('m','a','x','t','i','m','e'): {
1247 value_SetEnum(parent,command_FieldId_maxtime); ret = true; break;
1248 }
1249 case LE_STR7('m','o','v','e','_','i','n'): {
1250 value_SetEnum(parent,command_FieldId_move_in); ret = true; break;
1251 }
1252 case LE_STR7('m','s','g','t','y','p','e'): {
1253 value_SetEnum(parent,command_FieldId_msgtype); ret = true; break;
1254 }
1255 case LE_STR7('n','o','i','n','p','u','t'): {
1256 value_SetEnum(parent,command_FieldId_noinput); ret = true; break;
1257 }
1258 case LE_STR7('o','u','t','_','d','i','r'): {
1259 value_SetEnum(parent,command_FieldId_out_dir); ret = true; break;
1260 }
1261 case LE_STR7('p','a','c','k','a','g','e'): {
1262 value_SetEnum(parent,command_FieldId_package); ret = true; break;
1263 }
1264 case LE_STR7('p','a','g','e','d','i','r'): {
1265 value_SetEnum(parent,command_FieldId_pagedir); ret = true; break;
1266 }
1267 case LE_STR7('p','k','g','d','a','t','a'): {
1268 value_SetEnum(parent,command_FieldId_pkgdata); ret = true; break;
1269 }
1270 case LE_STR7('p','r','e','p','r','o','c'): {
1271 value_SetEnum(parent,command_FieldId_preproc); ret = true; break;
1272 }
1273 case LE_STR7('r','e','f','t','y','p','e'): {
1274 value_SetEnum(parent,command_FieldId_reftype); ret = true; break;
1275 }
1276 case LE_STR7('r','e','l','a','t','e','d'): {
1277 value_SetEnum(parent,command_FieldId_related); ret = true; break;
1278 }
1279 case LE_STR7('r','e','p','l','a','c','e'): {
1280 value_SetEnum(parent,command_FieldId_replace); ret = true; break;
1281 }
1282 case LE_STR7('s','a','n','d','b','o','x'): {
1283 value_SetEnum(parent,command_FieldId_sandbox); ret = true; break;
1284 }
1285 case LE_STR7('s','e','c','t','i','o','n'): {
1286 value_SetEnum(parent,command_FieldId_section); ret = true; break;
1287 }
1288 case LE_STR7('s','h','o','w','c','p','p'): {
1289 value_SetEnum(parent,command_FieldId_showcpp); ret = true; break;
1290 }
1291 case LE_STR7('s','h','o','w','l','o','c'): {
1292 value_SetEnum(parent,command_FieldId_showloc); ret = true; break;
1293 }
1294 case LE_STR7('s','h','o','w','r','e','c'): {
1295 value_SetEnum(parent,command_FieldId_showrec); ret = true; break;
1296 }
1297 case LE_STR7('s','o','r','t','f','l','d'): {
1298 value_SetEnum(parent,command_FieldId_sortfld); ret = true; break;
1299 }
1300 case LE_STR7('s','r','c','f','i','l','e'): {
1301 value_SetEnum(parent,command_FieldId_srcfile); ret = true; break;
1302 }
1303 case LE_STR7('s','u','b','s','e','t','2'): {
1304 value_SetEnum(parent,command_FieldId_subset2); ret = true; break;
1305 }
1306 case LE_STR7('s','u','m','m','a','r','y'): {
1307 value_SetEnum(parent,command_FieldId_summary); ret = true; break;
1308 }
1309 case LE_STR7('t','a','r','g','s','r','c'): {
1310 value_SetEnum(parent,command_FieldId_targsrc); ret = true; break;
1311 }
1312 case LE_STR7('t','i','m','e','o','u','t'): {
1313 value_SetEnum(parent,command_FieldId_timeout); ret = true; break;
1314 }
1315 case LE_STR7('t','y','p','e','t','a','g'): {
1316 value_SetEnum(parent,command_FieldId_typetag); ret = true; break;
1317 }
1318 case LE_STR7('w','o','r','k','d','i','r'): {
1319 value_SetEnum(parent,command_FieldId_workdir); ret = true; break;
1320 }
1321 }
1322 break;
1323 }
1324 case 8: {
1325 switch (algo::ReadLE64(rhs.elems)) {
1326 case LE_STR8('a','n','n','o','t','a','t','e'): {
1327 value_SetEnum(parent,command_FieldId_annotate); ret = true; break;
1328 }
1329 case LE_STR8('b','l','o','c','k','i','n','g'): {
1330 value_SetEnum(parent,command_FieldId_blocking); ret = true; break;
1331 }
1332 case LE_STR8('c','m','d','_','d','c','t','r'): {
1333 value_SetEnum(parent,command_FieldId_cmd_dctr); ret = true; break;
1334 }
1335 case LE_STR8('c','o','m','p','i','l','e','r'): {
1336 value_SetEnum(parent,command_FieldId_compiler); ret = true; break;
1337 }
1338 case LE_STR8('c','o','m','p','t','e','s','t'): {
1339 value_SetEnum(parent,command_FieldId_comptest); ret = true; break;
1340 }
1341 case LE_STR8('c','o','v','c','h','e','c','k'): {
1342 value_SetEnum(parent,command_FieldId_covcheck); ret = true; break;
1343 }
1344 case LE_STR8('c','o','v','e','r','i','t','y'): {
1345 value_SetEnum(parent,command_FieldId_coverity); ret = true; break;
1346 }
1347 case LE_STR8('c','r','e','a','t','e','d','b'): {
1348 value_SetEnum(parent,command_FieldId_createdb); ret = true; break;
1349 }
1350 case LE_STR8('d','a','t','a','_','d','i','r'): {
1351 value_SetEnum(parent,command_FieldId_data_dir); ret = true; break;
1352 }
1353 case LE_STR8('d','c','t','r','h','o','s','t'): {
1354 value_SetEnum(parent,command_FieldId_dctrhost); ret = true; break;
1355 }
1356 case LE_STR8('d','h','o','s','t','_','i','p'): {
1357 value_SetEnum(parent,command_FieldId_dhost_ip); ret = true; break;
1358 }
1359 case LE_STR8('d','o','w','n','l','o','a','d'): {
1360 value_SetEnum(parent,command_FieldId_download); ret = true; break;
1361 }
1362 case LE_STR8('g','e','n','e','r','a','t','e'): {
1363 value_SetEnum(parent,command_FieldId_generate); ret = true; break;
1364 }
1365 case LE_STR8('l','i','s','t','f','u','n','c'): {
1366 value_SetEnum(parent,command_FieldId_listfunc); ret = true; break;
1367 }
1368 case LE_STR8('l','i','s','t','i','n','c','l'): {
1369 value_SetEnum(parent,command_FieldId_listincl); ret = true; break;
1370 }
1371 case LE_STR8('m','a','x','g','r','o','u','p'): {
1372 value_SetEnum(parent,command_FieldId_maxgroup); ret = true; break;
1373 }
1374 case LE_STR8('m','e','m','c','h','e','c','k'): {
1375 value_SetEnum(parent,command_FieldId_memcheck); ret = true; break;
1376 }
1377 case LE_STR8('m','o','v','e','_','o','u','t'): {
1378 value_SetEnum(parent,command_FieldId_move_out); ret = true; break;
1379 }
1380 case LE_STR8('n','e','x','t','f','i','l','e'): {
1381 value_SetEnum(parent,command_FieldId_nextfile); ret = true; break;
1382 }
1383 case LE_STR8('n','u','l','l','a','b','l','e'): {
1384 value_SetEnum(parent,command_FieldId_nullable); ret = true; break;
1385 }
1386 case LE_STR8('p','a','t','h','c','o','m','p'): {
1387 value_SetEnum(parent,command_FieldId_pathcomp); ret = true; break;
1388 }
1389 case LE_STR8('p','o','o','l','t','y','p','e'): {
1390 value_SetEnum(parent,command_FieldId_pooltype); ret = true; break;
1391 }
1392 case LE_STR8('p','r','i','n','t','c','m','d'): {
1393 value_SetEnum(parent,command_FieldId_printcmd); ret = true; break;
1394 }
1395 case LE_STR8('r','e','n','a','m','e','t','o'): {
1396 value_SetEnum(parent,command_FieldId_renameto); ret = true; break;
1397 }
1398 case LE_STR8('s','e','l','e','c','t','o','r'): {
1399 value_SetEnum(parent,command_FieldId_selector); ret = true; break;
1400 }
1401 case LE_STR8('s','h','o','w','f','i','l','e'): {
1402 value_SetEnum(parent,command_FieldId_showfile); ret = true; break;
1403 }
1404 case LE_STR8('s','i','g','c','h','e','c','k'): {
1405 value_SetEnum(parent,command_FieldId_sigcheck); ret = true; break;
1406 }
1407 case LE_STR8('s','o','r','t','n','a','m','e'): {
1408 value_SetEnum(parent,command_FieldId_sortname); ret = true; break;
1409 }
1410 case LE_STR8('s','r','c','f','i','e','l','d'): {
1411 value_SetEnum(parent,command_FieldId_srcfield); ret = true; break;
1412 }
1413 case LE_STR8('s','s','i','m','f','i','l','e'): {
1414 value_SetEnum(parent,command_FieldId_ssimfile); ret = true; break;
1415 }
1416 case LE_STR8('t','e','s','t','p','r','o','b'): {
1417 value_SetEnum(parent,command_FieldId_testprob); ret = true; break;
1418 }
1419 case LE_STR8('u','n','i','t','t','e','s','t'): {
1420 value_SetEnum(parent,command_FieldId_unittest); ret = true; break;
1421 }
1422 case LE_STR8('w','i','k','i','s','i','t','e'): {
1423 value_SetEnum(parent,command_FieldId_wikisite); ret = true; break;
1424 }
1425 }
1426 break;
1427 }
1428 case 9: {
1429 switch (algo::ReadLE64(rhs.elems)) {
1430 case LE_STR8('a','d','d','_','r','e','s','e'): {
1431 if (memcmp(rhs.elems+8,"t",1)==0) { value_SetEnum(parent,command_FieldId_add_reset); ret = true; break; }
1432 break;
1433 }
1434 case LE_STR8('c','a','l','l','g','r','i','n'): {
1435 if (memcmp(rhs.elems+8,"d",1)==0) { value_SetEnum(parent,command_FieldId_callgrind); ret = true; break; }
1436 break;
1437 }
1438 case LE_STR8('c','h','e','c','k','a','b','l'): {
1439 if (memcmp(rhs.elems+8,"e",1)==0) { value_SetEnum(parent,command_FieldId_checkable); ret = true; break; }
1440 break;
1441 }
1442 case LE_STR8('c','l','e','a','n','_','r','u'): {
1443 if (memcmp(rhs.elems+8,"n",1)==0) { value_SetEnum(parent,command_FieldId_clean_run); ret = true; break; }
1444 break;
1445 }
1446 case LE_STR8('d','c','t','r','_','f','r','o'): {
1447 if (memcmp(rhs.elems+8,"m",1)==0) { value_SetEnum(parent,command_FieldId_dctr_from); ret = true; break; }
1448 break;
1449 }
1450 case LE_STR8('d','e','b','u','g','_','l','o'): {
1451 if (memcmp(rhs.elems+8,"g",1)==0) { value_SetEnum(parent,command_FieldId_debug_log); ret = true; break; }
1452 break;
1453 }
1454 case LE_STR8('f','u','z','z','s','t','r','a'): {
1455 if (memcmp(rhs.elems+8,"t",1)==0) { value_SetEnum(parent,command_FieldId_fuzzstrat); ret = true; break; }
1456 break;
1457 }
1458 case LE_STR8('i','n','p','u','t','f','i','l'): {
1459 if (memcmp(rhs.elems+8,"e",1)==0) { value_SetEnum(parent,command_FieldId_inputfile); ret = true; break; }
1460 break;
1461 }
1462 case LE_STR8('m','a','x','p','a','c','k','e'): {
1463 if (memcmp(rhs.elems+8,"t",1)==0) { value_SetEnum(parent,command_FieldId_maxpacket); ret = true; break; }
1464 break;
1465 }
1466 case LE_STR8('m','e','r','g','e','p','a','t'): {
1467 if (memcmp(rhs.elems+8,"h",1)==0) { value_SetEnum(parent,command_FieldId_mergepath); ret = true; break; }
1468 break;
1469 }
1470 case LE_STR8('n','o','_','r','e','b','a','s'): {
1471 if (memcmp(rhs.elems+8,"e",1)==0) { value_SetEnum(parent,command_FieldId_no_rebase); ret = true; break; }
1472 break;
1473 }
1474 case LE_STR8('n','o','r','m','a','l','i','z'): {
1475 if (memcmp(rhs.elems+8,"e",1)==0) { value_SetEnum(parent,command_FieldId_normalize); ret = true; break; }
1476 break;
1477 }
1478 case LE_STR8('p','e','r','f','_','s','e','c'): {
1479 if (memcmp(rhs.elems+8,"s",1)==0) { value_SetEnum(parent,command_FieldId_perf_secs); ret = true; break; }
1480 break;
1481 }
1482 case LE_STR8('r','e','c','v','d','e','l','a'): {
1483 if (memcmp(rhs.elems+8,"y",1)==0) { value_SetEnum(parent,command_FieldId_recvdelay); ret = true; break; }
1484 break;
1485 }
1486 case LE_STR8('r','e','p','r','o','f','i','l'): {
1487 if (memcmp(rhs.elems+8,"e",1)==0) { value_SetEnum(parent,command_FieldId_reprofile); ret = true; break; }
1488 break;
1489 }
1490 case LE_STR8('r','s','y','n','c','_','g','e'): {
1491 if (memcmp(rhs.elems+8,"t",1)==0) { value_SetEnum(parent,command_FieldId_rsync_get); ret = true; break; }
1492 break;
1493 }
1494 case LE_STR8('r','s','y','n','c','_','p','u'): {
1495 if (memcmp(rhs.elems+8,"t",1)==0) { value_SetEnum(parent,command_FieldId_rsync_put); ret = true; break; }
1496 break;
1497 }
1498 case LE_STR8('s','e','p','a','r','a','t','o'): {
1499 if (memcmp(rhs.elems+8,"r",1)==0) { value_SetEnum(parent,command_FieldId_separator); ret = true; break; }
1500 break;
1501 }
1502 case LE_STR8('s','k','i','p','_','i','n','i'): {
1503 if (memcmp(rhs.elems+8,"t",1)==0) { value_SetEnum(parent,command_FieldId_skip_init); ret = true; break; }
1504 break;
1505 }
1506 case LE_STR8('s','t','r','a','y','f','i','l'): {
1507 if (memcmp(rhs.elems+8,"e",1)==0) { value_SetEnum(parent,command_FieldId_strayfile); ret = true; break; }
1508 break;
1509 }
1510 case LE_STR8('w','i','k','i','_','k','i','l'): {
1511 if (memcmp(rhs.elems+8,"l",1)==0) { value_SetEnum(parent,command_FieldId_wiki_kill); ret = true; break; }
1512 break;
1513 }
1514 case LE_STR8('x','m','l','p','r','e','t','t'): {
1515 if (memcmp(rhs.elems+8,"y",1)==0) { value_SetEnum(parent,command_FieldId_xmlpretty); ret = true; break; }
1516 break;
1517 }
1518 }
1519 break;
1520 }
1521 case 10: {
1522 switch (algo::ReadLE64(rhs.elems)) {
1523 case LE_STR8('c','a','t','c','h','t','h','r'): {
1524 if (memcmp(rhs.elems+8,"ow",2)==0) { value_SetEnum(parent,command_FieldId_catchthrow); ret = true; break; }
1525 break;
1526 }
1527 case LE_STR8('c','h','e','c','k','c','l','e'): {
1528 if (memcmp(rhs.elems+8,"an",2)==0) { value_SetEnum(parent,command_FieldId_checkclean); ret = true; break; }
1529 break;
1530 }
1531 case LE_STR8('c','o','n','f','i','g','_','s'): {
1532 if (memcmp(rhs.elems+8,"sh",2)==0) { value_SetEnum(parent,command_FieldId_config_ssh); ret = true; break; }
1533 break;
1534 }
1535 case LE_STR8('c','o','v','c','a','p','t','u'): {
1536 if (memcmp(rhs.elems+8,"re",2)==0) { value_SetEnum(parent,command_FieldId_covcapture); ret = true; break; }
1537 break;
1538 }
1539 case LE_STR8('d','h','o','s','t','_','u','s'): {
1540 if (memcmp(rhs.elems+8,"er",2)==0) { value_SetEnum(parent,command_FieldId_dhost_user); ret = true; break; }
1541 break;
1542 }
1543 case LE_STR8('g','t','b','l','a','c','t','t'): {
1544 if (memcmp(rhs.elems+8,"st",2)==0) { value_SetEnum(parent,command_FieldId_gtblacttst); ret = true; break; }
1545 break;
1546 }
1547 case LE_STR8('k','e','e','p','_','f','i','l'): {
1548 if (memcmp(rhs.elems+8,"es",2)==0) { value_SetEnum(parent,command_FieldId_keep_files); ret = true; break; }
1549 break;
1550 }
1551 case LE_STR8('n','e','e','d','s','_','w','o'): {
1552 if (memcmp(rhs.elems+8,"rk",2)==0) { value_SetEnum(parent,command_FieldId_needs_work); ret = true; break; }
1553 break;
1554 }
1555 case LE_STR8('p','r','i','n','t','i','n','p'): {
1556 if (memcmp(rhs.elems+8,"ut",2)==0) { value_SetEnum(parent,command_FieldId_printinput); ret = true; break; }
1557 break;
1558 }
1559 case LE_STR8('r','s','y','n','c','_','o','p'): {
1560 if (memcmp(rhs.elems+8,"ts",2)==0) { value_SetEnum(parent,command_FieldId_rsync_opts); ret = true; break; }
1561 break;
1562 }
1563 case LE_STR8('s','c','r','i','p','t','_','d'): {
1564 if (memcmp(rhs.elems+8,"ir",2)==0) { value_SetEnum(parent,command_FieldId_script_dir); ret = true; break; }
1565 break;
1566 }
1567 case LE_STR8('s','c','r','i','p','t','f','i'): {
1568 if (memcmp(rhs.elems+8,"le",2)==0) { value_SetEnum(parent,command_FieldId_scriptfile); ret = true; break; }
1569 break;
1570 }
1571 case LE_STR8('s','h','o','w','s','t','a','t'): {
1572 if (memcmp(rhs.elems+8,"ic",2)==0) { value_SetEnum(parent,command_FieldId_showstatic); ret = true; break; }
1573 break;
1574 }
1575 case LE_STR8('w','i','k','i','_','s','t','a'): {
1576 if (memcmp(rhs.elems+8,"rt",2)==0) { value_SetEnum(parent,command_FieldId_wiki_start); ret = true; break; }
1577 break;
1578 }
1579 case LE_STR8('w','r','i','t','e','_','o','u'): {
1580 if (memcmp(rhs.elems+8,"rs",2)==0) { value_SetEnum(parent,command_FieldId_write_ours); ret = true; break; }
1581 break;
1582 }
1583 case LE_STR8('w','t','b','l','a','c','t','t'): {
1584 if (memcmp(rhs.elems+8,"st",2)==0) { value_SetEnum(parent,command_FieldId_wtblacttst); ret = true; break; }
1585 break;
1586 }
1587 }
1588 break;
1589 }
1590 case 11: {
1591 switch (algo::ReadLE64(rhs.elems)) {
1592 case LE_STR8('b','u','i','l','d','_','q','u'): {
1593 if (memcmp(rhs.elems+8,"iet",3)==0) { value_SetEnum(parent,command_FieldId_build_quiet); ret = true; break; }
1594 break;
1595 }
1596 case LE_STR8('f','i','l','e','_','p','r','e'): {
1597 if (memcmp(rhs.elems+8,"fix",3)==0) { value_SetEnum(parent,command_FieldId_file_prefix); ret = true; break; }
1598 break;
1599 }
1600 case LE_STR8('i','g','n','o','r','e','Q','u'): {
1601 if (memcmp(rhs.elems+8,"ote",3)==0) { value_SetEnum(parent,command_FieldId_ignoreQuote); ret = true; break; }
1602 break;
1603 }
1604 case LE_STR8('m','s','g','s','i','z','e','_'): {
1605 if (memcmp(rhs.elems+8,"min",3)==0) { value_SetEnum(parent,command_FieldId_msgsize_min); ret = true; break; }
1606 if (memcmp(rhs.elems+8,"max",3)==0) { value_SetEnum(parent,command_FieldId_msgsize_max); ret = true; break; }
1607 break;
1608 }
1609 case LE_STR8('n','o','t','s','s','i','m','f'): {
1610 if (memcmp(rhs.elems+8,"ile",3)==0) { value_SetEnum(parent,command_FieldId_notssimfile); ret = true; break; }
1611 break;
1612 }
1613 case LE_STR8('s','e','r','v','e','_','p','a'): {
1614 if (memcmp(rhs.elems+8,"ges",3)==0) { value_SetEnum(parent,command_FieldId_serve_pages); ret = true; break; }
1615 break;
1616 }
1617 case LE_STR8('s','h','o','w','s','o','r','t'): {
1618 if (memcmp(rhs.elems+8,"key",3)==0) { value_SetEnum(parent,command_FieldId_showsortkey); ret = true; break; }
1619 break;
1620 }
1621 case LE_STR8('t','o','c','a','m','e','l','c'): {
1622 if (memcmp(rhs.elems+8,"ase",3)==0) { value_SetEnum(parent,command_FieldId_tocamelcase); ret = true; break; }
1623 break;
1624 }
1625 case LE_STR8('u','p','d','a','t','e','p','r'): {
1626 if (memcmp(rhs.elems+8,"oto",3)==0) { value_SetEnum(parent,command_FieldId_updateproto); ret = true; break; }
1627 break;
1628 }
1629 case LE_STR8('w','i','k','i','_','u','p','d'): {
1630 if (memcmp(rhs.elems+8,"ate",3)==0) { value_SetEnum(parent,command_FieldId_wiki_update); ret = true; break; }
1631 break;
1632 }
1633 }
1634 break;
1635 }
1636 case 12: {
1637 switch (algo::ReadLE64(rhs.elems)) {
1638 case LE_STR8('a','u','t','h','d','i','r','_'): {
1639 if (memcmp(rhs.elems+8,"dflt",4)==0) { value_SetEnum(parent,command_FieldId_authdir_dflt); ret = true; break; }
1640 break;
1641 }
1642 case LE_STR8('d','h','o','s','t','_','e','x'): {
1643 if (memcmp(rhs.elems+8,"t_ip",4)==0) { value_SetEnum(parent,command_FieldId_dhost_ext_ip); ret = true; break; }
1644 break;
1645 }
1646 case LE_STR8('f','a','s','t','_','m','s','g'): {
1647 if (memcmp(rhs.elems+8,"_max",4)==0) { value_SetEnum(parent,command_FieldId_fast_msg_max); ret = true; break; }
1648 break;
1649 }
1650 case LE_STR8('f','o','l','l','o','w','_','c'): {
1651 if (memcmp(rhs.elems+8,"hild",4)==0) { value_SetEnum(parent,command_FieldId_follow_child); ret = true; break; }
1652 break;
1653 }
1654 case LE_STR8('o','u','t','s','e','p','a','r'): {
1655 if (memcmp(rhs.elems+8,"ator",4)==0) { value_SetEnum(parent,command_FieldId_outseparator); ret = true; break; }
1656 break;
1657 }
1658 case LE_STR8('r','e','c','v','d','e','l','a'): {
1659 if (memcmp(rhs.elems+8,"y_ns",4)==0) { value_SetEnum(parent,command_FieldId_recvdelay_ns); ret = true; break; }
1660 break;
1661 }
1662 case LE_STR8('s','e','n','d','d','e','l','a'): {
1663 if (memcmp(rhs.elems+8,"y_ns",4)==0) { value_SetEnum(parent,command_FieldId_senddelay_ns); ret = true; break; }
1664 break;
1665 }
1666 case LE_STR8('s','e','r','v','e','_','v','e'): {
1667 if (memcmp(rhs.elems+8,"rify",4)==0) { value_SetEnum(parent,command_FieldId_serve_verify); ret = true; break; }
1668 break;
1669 }
1670 case LE_STR8('t','o','l','o','w','e','r','u'): {
1671 if (memcmp(rhs.elems+8,"nder",4)==0) { value_SetEnum(parent,command_FieldId_tolowerunder); ret = true; break; }
1672 break;
1673 }
1674 case LE_STR8('w','i','k','i','_','e','n','v'): {
1675 if (memcmp(rhs.elems+8,"node",4)==0) { value_SetEnum(parent,command_FieldId_wiki_envnode); ret = true; break; }
1676 break;
1677 }
1678 }
1679 break;
1680 }
1681 case 13: {
1682 switch (algo::ReadLE64(rhs.elems)) {
1683 case LE_STR8('o','p','t','s','_','n','u','m'): {
1684 if (memcmp(rhs.elems+8,"bered",5)==0) { value_SetEnum(parent,command_FieldId_opts_numbered); ret = true; break; }
1685 break;
1686 }
1687 case LE_STR8('p','r','e','f','e','r','_','s'): {
1688 if (memcmp(rhs.elems+8,"igned",5)==0) { value_SetEnum(parent,command_FieldId_prefer_signed); ret = true; break; }
1689 break;
1690 }
1691 case LE_STR8('s','k','i','p','_','g','i','t'): {
1692 if (memcmp(rhs.elems+8,"_init",5)==0) { value_SetEnum(parent,command_FieldId_skip_git_init); ret = true; break; }
1693 break;
1694 }
1695 case LE_STR8('w','r','i','t','e','s','s','i'): {
1696 if (memcmp(rhs.elems+8,"mfile",5)==0) { value_SetEnum(parent,command_FieldId_writessimfile); ret = true; break; }
1697 break;
1698 }
1699 }
1700 break;
1701 }
1702 case 14: {
1703 switch (algo::ReadLE64(rhs.elems)) {
1704 case LE_STR8('c','o','n','f','i','g','_','s'): {
1705 if (memcmp(rhs.elems+8,"sh_vpn",6)==0) { value_SetEnum(parent,command_FieldId_config_ssh_vpn); ret = true; break; }
1706 break;
1707 }
1708 case LE_STR8('d','h','o','s','t','_','e','x'): {
1709 if (memcmp(rhs.elems+8,"t_port",6)==0) { value_SetEnum(parent,command_FieldId_dhost_ext_port); ret = true; break; }
1710 break;
1711 }
1712 case LE_STR8('g','e','n','e','r','a','t','e'): {
1713 if (memcmp(rhs.elems+8,"_build",6)==0) { value_SetEnum(parent,command_FieldId_generate_build); ret = true; break; }
1714 break;
1715 }
1716 case LE_STR8('s','e','r','v','e','_','d','c'): {
1717 if (memcmp(rhs.elems+8,"trhost",6)==0) { value_SetEnum(parent,command_FieldId_serve_dctrhost); ret = true; break; }
1718 break;
1719 }
1720 }
1721 break;
1722 }
1723 case 15: {
1724 switch (algo::ReadLE64(rhs.elems)) {
1725 case LE_STR8('c','h','e','c','k','_','u','n'): {
1726 if (memcmp(rhs.elems+8,"tracked",7)==0) { value_SetEnum(parent,command_FieldId_check_untracked); ret = true; break; }
1727 break;
1728 }
1729 case LE_STR8('p','e','r','t','e','s','t','_'): {
1730 if (memcmp(rhs.elems+8,"timeout",7)==0) { value_SetEnum(parent,command_FieldId_pertest_timeout); ret = true; break; }
1731 break;
1732 }
1733 case LE_STR8('p','r','e','s','e','r','v','e'): {
1734 if (memcmp(rhs.elems+8,"_footer",7)==0) { value_SetEnum(parent,command_FieldId_preserve_footer); ret = true; break; }
1735 break;
1736 }
1737 case LE_STR8('r','a','n','d','o','m','i','z'): {
1738 if (memcmp(rhs.elems+8,"e_ports",7)==0) { value_SetEnum(parent,command_FieldId_randomize_ports); ret = true; break; }
1739 break;
1740 }
1741 }
1742 break;
1743 }
1744 case 16: {
1745 switch (algo::ReadLE64(rhs.elems)) {
1746 case LE_STR8('e','x','c','l','u','d','e','_'): {
1747 if (memcmp(rhs.elems+8,"subpages",8)==0) { value_SetEnum(parent,command_FieldId_exclude_subpages); ret = true; break; }
1748 break;
1749 }
1750 case LE_STR8('u','p','d','a','t','e','_','c'): {
1751 if (memcmp(rhs.elems+8,"opyright",8)==0) { value_SetEnum(parent,command_FieldId_update_copyright); ret = true; break; }
1752 break;
1753 }
1754 case LE_STR8('w','i','k','i','_','c','l','e'): {
1755 if (memcmp(rhs.elems+8,"an_start",8)==0) { value_SetEnum(parent,command_FieldId_wiki_clean_start); ret = true; break; }
1756 break;
1757 }
1758 case LE_STR8('w','i','k','i','_','u','p','d'): {
1759 if (memcmp(rhs.elems+8,"ate_help",8)==0) { value_SetEnum(parent,command_FieldId_wiki_update_help); ret = true; break; }
1760 break;
1761 }
1762 }
1763 break;
1764 }
1765 case 17: {
1766 switch (algo::ReadLE64(rhs.elems)) {
1767 case LE_STR8('i','g','n','o','r','e','_','s'): {
1768 if (memcmp(rhs.elems+8,"aved_edit",9)==0) { value_SetEnum(parent,command_FieldId_ignore_saved_edit); ret = true; break; }
1769 break;
1770 }
1771 }
1772 break;
1773 }
1774 case 18: {
1775 switch (algo::ReadLE64(rhs.elems)) {
1776 case LE_STR8('w','i','k','i','_','u','p','d'): {
1777 if (memcmp(rhs.elems+8,"ate_fields",10)==0) { value_SetEnum(parent,command_FieldId_wiki_update_fields); ret = true; break; }
1778 break;
1779 }
1780 }
1781 break;
1782 }
1783 case 21: {
1784 switch (algo::ReadLE64(rhs.elems)) {
1785 case LE_STR8('b','u','i','l','d','_','f','a'): {
1786 if (memcmp(rhs.elems+8,"il_on_warning",13)==0) { value_SetEnum(parent,command_FieldId_build_fail_on_warning); ret = true; break; }
1787 break;
1788 }
1789 }
1790 break;
1791 }
1792 case 24: {
1793 switch (algo::ReadLE64(rhs.elems)) {
1794 case LE_STR8('s','h','o','w','_','g','i','t'): {
1795 if (memcmp(rhs.elems+8,"lab_system_notes",16)==0) { value_SetEnum(parent,command_FieldId_show_gitlab_system_notes); ret = true; break; }
1796 break;
1797 }
1798 }
1799 break;
1800 }
1801 }
1802 return ret;
1803}
1804
1805// --- command.FieldId.value.SetStrptr
1806// Convert string to field.
1807// If the string is invalid, set numeric value to DFLT
1808void command::value_SetStrptr(command::FieldId& parent, algo::strptr rhs, command_FieldIdEnum dflt) {
1809 if (!value_SetStrptrMaybe(parent,rhs)) value_SetEnum(parent,dflt);
1810}
1811
1812// --- command.FieldId.value.ReadStrptrMaybe
1813// Convert string to field. Return success value
1814bool command::value_ReadStrptrMaybe(command::FieldId& parent, algo::strptr rhs) {
1815 bool retval = false;
1816 retval = value_SetStrptrMaybe(parent,rhs); // try symbol conversion
1817 if (!retval) { // didn't work? try reading as underlying type
1818 retval = i32_ReadStrptrMaybe(parent.value,rhs);
1819 }
1820 return retval;
1821}
1822
1823// --- command.FieldId..ReadStrptrMaybe
1824// Read fields of command::FieldId from an ascii string.
1825// The format of the string is the format of the command::FieldId's only field
1826bool command::FieldId_ReadStrptrMaybe(command::FieldId &parent, algo::strptr in_str) {
1827 bool retval = true;
1828 retval = retval && value_ReadStrptrMaybe(parent, in_str);
1829 return retval;
1830}
1831
1832// --- command.FieldId..Print
1833// print string representation of ROW to string STR
1834// cfmt:command.FieldId.String printfmt:Raw
1835void command::FieldId_Print(command::FieldId& row, algo::cstring& str) {
1836 command::value_Print(row, str);
1837}
1838
1839// --- command.abt.target.Print
1840// Print back to string
1841void command::target_Print(command::abt& parent, algo::cstring &out) {
1842 Regx_Print(parent.target, out);
1843}
1844
1845// --- command.abt.target.ReadStrptrMaybe
1846// Read Regx from string
1847// Convert string to field. Return success value
1848bool command::target_ReadStrptrMaybe(command::abt& parent, algo::strptr in) {
1849 bool retval = true;
1850 Regx_ReadSql(parent.target, in, true);
1851 return retval;
1852}
1853
1854// --- command.abt.disas.Print
1855// Print back to string
1856void command::disas_Print(command::abt& parent, algo::cstring &out) {
1857 Regx_Print(parent.disas, out);
1858}
1859
1860// --- command.abt.disas.ReadStrptrMaybe
1861// Read Regx from string
1862// Convert string to field. Return success value
1863bool command::disas_ReadStrptrMaybe(command::abt& parent, algo::strptr in) {
1864 bool retval = true;
1865 Regx_ReadSql(parent.disas, in, false);
1866 return retval;
1867}
1868
1869// --- command.abt.cache.ToCstr
1870// Convert numeric value of field to one of predefined string constants.
1871// If string is found, return a static C string. Otherwise, return NULL.
1872const char* command::cache_ToCstr(const command::abt& parent) {
1873 const char *ret = NULL;
1874 switch(cache_GetEnum(parent)) {
1875 case command_abt_cache_auto : ret = "auto"; break;
1876 case command_abt_cache_none : ret = "none"; break;
1877 case command_abt_cache_gcache : ret = "gcache"; break;
1878 case command_abt_cache_gcache_force: ret = "gcache-force"; break;
1879 case command_abt_cache_ccache : ret = "ccache"; break;
1880 }
1881 return ret;
1882}
1883
1884// --- command.abt.cache.Print
1885// Convert cache to a string. First, attempt conversion to a known string.
1886// If no string matches, print cache as a numeric value.
1887void command::cache_Print(const command::abt& parent, algo::cstring &lhs) {
1888 const char *strval = cache_ToCstr(parent);
1889 if (strval) {
1890 lhs << strval;
1891 } else {
1892 lhs << parent.cache;
1893 }
1894}
1895
1896// --- command.abt.cache.SetStrptrMaybe
1897// Convert string to field.
1898// If the string is invalid, do not modify field and return false.
1899// In case of success, return true
1900bool command::cache_SetStrptrMaybe(command::abt& parent, algo::strptr rhs) {
1901 bool ret = false;
1902 switch (elems_N(rhs)) {
1903 case 4: {
1904 switch (u64(algo::ReadLE32(rhs.elems))) {
1905 case LE_STR4('a','u','t','o'): {
1906 cache_SetEnum(parent,command_abt_cache_auto); ret = true; break;
1907 }
1908 case LE_STR4('n','o','n','e'): {
1909 cache_SetEnum(parent,command_abt_cache_none); ret = true; break;
1910 }
1911 }
1912 break;
1913 }
1914 case 6: {
1915 switch (u64(algo::ReadLE32(rhs.elems))|(u64(algo::ReadLE16(rhs.elems+4))<<32)) {
1916 case LE_STR6('c','c','a','c','h','e'): {
1917 cache_SetEnum(parent,command_abt_cache_ccache); ret = true; break;
1918 }
1919 case LE_STR6('g','c','a','c','h','e'): {
1920 cache_SetEnum(parent,command_abt_cache_gcache); ret = true; break;
1921 }
1922 }
1923 break;
1924 }
1925 case 12: {
1926 switch (algo::ReadLE64(rhs.elems)) {
1927 case LE_STR8('g','c','a','c','h','e','-','f'): {
1928 if (memcmp(rhs.elems+8,"orce",4)==0) { cache_SetEnum(parent,command_abt_cache_gcache_force); ret = true; break; }
1929 break;
1930 }
1931 }
1932 break;
1933 }
1934 }
1935 return ret;
1936}
1937
1938// --- command.abt.cache.SetStrptr
1939// Convert string to field.
1940// If the string is invalid, set numeric value to DFLT
1941void command::cache_SetStrptr(command::abt& parent, algo::strptr rhs, command_abt_cache_Enum dflt) {
1942 if (!cache_SetStrptrMaybe(parent,rhs)) cache_SetEnum(parent,dflt);
1943}
1944
1945// --- command.abt.cache.ReadStrptrMaybe
1946// Convert string to field. Return success value
1947bool command::cache_ReadStrptrMaybe(command::abt& parent, algo::strptr rhs) {
1948 bool retval = false;
1949 retval = cache_SetStrptrMaybe(parent,rhs); // try symbol conversion
1950 if (!retval) { // didn't work? try reading as underlying type
1951 retval = u8_ReadStrptrMaybe(parent.cache,rhs);
1952 }
1953 return retval;
1954}
1955
1956// --- command.abt..ReadFieldMaybe
1957bool command::abt_ReadFieldMaybe(command::abt& parent, algo::strptr field, algo::strptr strval) {
1958 bool retval = true;
1959 command::FieldId field_id;
1960 (void)value_SetStrptrMaybe(field_id,field);
1961 switch(field_id) {
1962 case command_FieldId_target: {
1963 retval = target_ReadStrptrMaybe(parent, strval);
1964 break;
1965 }
1966 case command_FieldId_in: {
1967 retval = algo::cstring_ReadStrptrMaybe(parent.in, strval);
1968 break;
1969 }
1970 case command_FieldId_out_dir: {
1971 retval = algo::cstring_ReadStrptrMaybe(parent.out_dir, strval);
1972 break;
1973 }
1974 case command_FieldId_cfg: {
1975 retval = algo::Smallstr50_ReadStrptrMaybe(parent.cfg, strval);
1976 break;
1977 }
1978 case command_FieldId_compiler: {
1979 retval = algo::Smallstr50_ReadStrptrMaybe(parent.compiler, strval);
1980 break;
1981 }
1982 case command_FieldId_uname: {
1983 retval = algo::Smallstr50_ReadStrptrMaybe(parent.uname, strval);
1984 break;
1985 }
1986 case command_FieldId_arch: {
1987 retval = algo::Smallstr50_ReadStrptrMaybe(parent.arch, strval);
1988 break;
1989 }
1990 case command_FieldId_ood: {
1991 retval = bool_ReadStrptrMaybe(parent.ood, strval);
1992 break;
1993 }
1994 case command_FieldId_list: {
1995 retval = bool_ReadStrptrMaybe(parent.list, strval);
1996 break;
1997 }
1998 case command_FieldId_listincl: {
1999 retval = bool_ReadStrptrMaybe(parent.listincl, strval);
2000 break;
2001 }
2002 case command_FieldId_build: {
2003 retval = bool_ReadStrptrMaybe(parent.build, strval);
2004 break;
2005 }
2006 case command_FieldId_preproc: {
2007 retval = bool_ReadStrptrMaybe(parent.preproc, strval);
2008 break;
2009 }
2010 case command_FieldId_clean: {
2011 retval = bool_ReadStrptrMaybe(parent.clean, strval);
2012 break;
2013 }
2014 case command_FieldId_dry_run: {
2015 retval = bool_ReadStrptrMaybe(parent.dry_run, strval);
2016 break;
2017 }
2018 case command_FieldId_maxjobs: {
2019 retval = i32_ReadStrptrMaybe(parent.maxjobs, strval);
2020 break;
2021 }
2022 case command_FieldId_printcmd: {
2023 retval = bool_ReadStrptrMaybe(parent.printcmd, strval);
2024 break;
2025 }
2026 case command_FieldId_force: {
2027 retval = bool_ReadStrptrMaybe(parent.force, strval);
2028 break;
2029 }
2030 case command_FieldId_install: {
2031 retval = bool_ReadStrptrMaybe(parent.install, strval);
2032 break;
2033 }
2034 case command_FieldId_coverity: {
2035 retval = bool_ReadStrptrMaybe(parent.coverity, strval);
2036 break;
2037 }
2038 case command_FieldId_package: {
2039 retval = algo::cstring_ReadStrptrMaybe(parent.package, strval);
2040 break;
2041 }
2042 case command_FieldId_maxerr: {
2043 retval = u32_ReadStrptrMaybe(parent.maxerr, strval);
2044 break;
2045 }
2046 case command_FieldId_disas: {
2047 retval = disas_ReadStrptrMaybe(parent, strval);
2048 break;
2049 }
2050 case command_FieldId_report: {
2051 retval = bool_ReadStrptrMaybe(parent.report, strval);
2052 break;
2053 }
2054 case command_FieldId_jcdb: {
2055 retval = algo::cstring_ReadStrptrMaybe(parent.jcdb, strval);
2056 break;
2057 }
2058 case command_FieldId_cache: {
2059 retval = cache_ReadStrptrMaybe(parent, strval);
2060 break;
2061 }
2062 default: break;
2063 }
2064 if (!retval) {
2065 algo_lib::AppendErrtext("attr",field);
2066 }
2067 return retval;
2068}
2069
2070// --- command.abt..ReadTupleMaybe
2071// Read fields of command::abt from attributes of ascii tuple TUPLE
2072bool command::abt_ReadTupleMaybe(command::abt &parent, algo::Tuple &tuple) {
2073 bool retval = true;
2074 int anon_idx = 0;
2075 ind_beg(algo::Tuple_attrs_curs,attr,tuple) {
2076 if (ch_N(attr.name) == 0) {
2077 attr.name = abt_GetAnon(parent, anon_idx++);
2078 }
2079 retval = abt_ReadFieldMaybe(parent, attr.name, attr.value);
2080 if (!retval) {
2081 break;
2082 }
2083 }ind_end;
2084 return retval;
2085}
2086
2087// --- command.abt..Init
2088// Set all fields to initial values.
2089void command::abt_Init(command::abt& parent) {
2090 Regx_ReadSql(parent.target, "", true);
2091 parent.in = algo::strptr("data");
2092 parent.out_dir = algo::strptr("");
2093 parent.cfg = algo::strptr("");
2094 parent.compiler = algo::strptr("");
2095 parent.uname = algo::strptr("");
2096 parent.arch = algo::strptr("");
2097 parent.ood = bool(false);
2098 parent.list = bool(false);
2099 parent.listincl = bool(false);
2100 parent.build = bool(false);
2101 parent.preproc = bool(false);
2102 parent.clean = bool(false);
2103 parent.dry_run = bool(false);
2104 parent.maxjobs = i32(0);
2105 parent.printcmd = bool(false);
2106 parent.force = bool(false);
2107 parent.install = bool(false);
2108 parent.coverity = bool(false);
2109 parent.package = algo::strptr("");
2110 parent.maxerr = u32(100);
2111 Regx_ReadSql(parent.disas, "", true);
2112 parent.report = bool(true);
2113 parent.jcdb = algo::strptr("");
2114 parent.cache = u8(0);
2115}
2116
2117// --- command.abt..ToCmdline
2118// Convenience function that returns a full command line
2119// Assume command is in a directory called bin
2120tempstr command::abt_ToCmdline(command::abt& row) {
2121 tempstr ret;
2122 ret << "bin/abt ";
2123 abt_PrintArgv(row, ret);
2124 // inherit less intense verbose, debug options
2125 for (int i = 1; i < algo_lib::_db.cmdline.verbose; i++) {
2126 ret << " -verbose";
2127 }
2128 for (int i = 1; i < algo_lib::_db.cmdline.debug; i++) {
2129 ret << " -debug";
2130 }
2131 return ret;
2132}
2133
2134// --- command.abt..PrintArgv
2135// print string representation of ROW to string STR
2136// cfmt:command.abt.Argv printfmt:Auto
2137void command::abt_PrintArgv(command::abt& row, algo::cstring& str) {
2138 algo::tempstr temp;
2139 (void)temp;
2140 (void)str;
2141 ch_RemoveAll(temp);
2142 command::target_Print(const_cast<command::abt&>(row), temp);
2143 str << " -target:";
2144 strptr_PrintBash(temp,str);
2145 if (!(row.in == "data")) {
2146 ch_RemoveAll(temp);
2147 cstring_Print(row.in, temp);
2148 str << " -in:";
2149 strptr_PrintBash(temp,str);
2150 }
2151 if (!(row.out_dir == "")) {
2152 ch_RemoveAll(temp);
2153 cstring_Print(row.out_dir, temp);
2154 str << " -out_dir:";
2155 strptr_PrintBash(temp,str);
2156 }
2157 if (!(row.cfg == "")) {
2158 ch_RemoveAll(temp);
2159 Smallstr50_Print(row.cfg, temp);
2160 str << " -cfg:";
2161 strptr_PrintBash(temp,str);
2162 }
2163 if (!(row.compiler == "")) {
2164 ch_RemoveAll(temp);
2165 Smallstr50_Print(row.compiler, temp);
2166 str << " -compiler:";
2167 strptr_PrintBash(temp,str);
2168 }
2169 if (!(row.uname == "")) {
2170 ch_RemoveAll(temp);
2171 Smallstr50_Print(row.uname, temp);
2172 str << " -uname:";
2173 strptr_PrintBash(temp,str);
2174 }
2175 if (!(row.arch == "")) {
2176 ch_RemoveAll(temp);
2177 Smallstr50_Print(row.arch, temp);
2178 str << " -arch:";
2179 strptr_PrintBash(temp,str);
2180 }
2181 if (!(row.ood == false)) {
2182 ch_RemoveAll(temp);
2183 bool_Print(row.ood, temp);
2184 str << " -ood:";
2185 strptr_PrintBash(temp,str);
2186 }
2187 if (!(row.list == false)) {
2188 ch_RemoveAll(temp);
2189 bool_Print(row.list, temp);
2190 str << " -list:";
2191 strptr_PrintBash(temp,str);
2192 }
2193 if (!(row.listincl == false)) {
2194 ch_RemoveAll(temp);
2195 bool_Print(row.listincl, temp);
2196 str << " -listincl:";
2197 strptr_PrintBash(temp,str);
2198 }
2199 if (!(row.build == false)) {
2200 ch_RemoveAll(temp);
2201 bool_Print(row.build, temp);
2202 str << " -build:";
2203 strptr_PrintBash(temp,str);
2204 }
2205 if (!(row.preproc == false)) {
2206 ch_RemoveAll(temp);
2207 bool_Print(row.preproc, temp);
2208 str << " -preproc:";
2209 strptr_PrintBash(temp,str);
2210 }
2211 if (!(row.clean == false)) {
2212 ch_RemoveAll(temp);
2213 bool_Print(row.clean, temp);
2214 str << " -clean:";
2215 strptr_PrintBash(temp,str);
2216 }
2217 if (!(row.dry_run == false)) {
2218 ch_RemoveAll(temp);
2219 bool_Print(row.dry_run, temp);
2220 str << " -dry_run:";
2221 strptr_PrintBash(temp,str);
2222 }
2223 if (!(row.maxjobs == 0)) {
2224 ch_RemoveAll(temp);
2225 i32_Print(row.maxjobs, temp);
2226 str << " -maxjobs:";
2227 strptr_PrintBash(temp,str);
2228 }
2229 if (!(row.printcmd == false)) {
2230 ch_RemoveAll(temp);
2231 bool_Print(row.printcmd, temp);
2232 str << " -printcmd:";
2233 strptr_PrintBash(temp,str);
2234 }
2235 if (!(row.force == false)) {
2236 ch_RemoveAll(temp);
2237 bool_Print(row.force, temp);
2238 str << " -force:";
2239 strptr_PrintBash(temp,str);
2240 }
2241 if (!(row.install == false)) {
2242 ch_RemoveAll(temp);
2243 bool_Print(row.install, temp);
2244 str << " -install:";
2245 strptr_PrintBash(temp,str);
2246 }
2247 if (!(row.coverity == false)) {
2248 ch_RemoveAll(temp);
2249 bool_Print(row.coverity, temp);
2250 str << " -coverity:";
2251 strptr_PrintBash(temp,str);
2252 }
2253 if (!(row.package == "")) {
2254 ch_RemoveAll(temp);
2255 cstring_Print(row.package, temp);
2256 str << " -package:";
2257 strptr_PrintBash(temp,str);
2258 }
2259 if (!(row.maxerr == 100)) {
2260 ch_RemoveAll(temp);
2261 u32_Print(row.maxerr, temp);
2262 str << " -maxerr:";
2263 strptr_PrintBash(temp,str);
2264 }
2265 if (!(row.disas.expr == "")) {
2266 ch_RemoveAll(temp);
2267 command::disas_Print(const_cast<command::abt&>(row), temp);
2268 str << " -disas:";
2269 strptr_PrintBash(temp,str);
2270 }
2271 if (!(row.report == true)) {
2272 ch_RemoveAll(temp);
2273 bool_Print(row.report, temp);
2274 str << " -report:";
2275 strptr_PrintBash(temp,str);
2276 }
2277 if (!(row.jcdb == "")) {
2278 ch_RemoveAll(temp);
2279 cstring_Print(row.jcdb, temp);
2280 str << " -jcdb:";
2281 strptr_PrintBash(temp,str);
2282 }
2283 if (!(row.cache == 0)) {
2284 ch_RemoveAll(temp);
2285 command::cache_Print(const_cast<command::abt&>(row), temp);
2286 str << " -cache:";
2287 strptr_PrintBash(temp,str);
2288 }
2289}
2290
2291// --- command.abt..GetAnon
2292algo::strptr command::abt_GetAnon(command::abt &parent, i32 idx) {
2293 (void)parent;//only to avoid -Wunused-parameter
2294 switch(idx) {
2295 case(0): return strptr("target", 6);
2296 default: return algo::strptr();
2297 }
2298}
2299
2300// --- command.abt..NArgs
2301// Used with command lines
2302// Return # of command-line arguments that must follow this argument
2303// If FIELD is invalid, return -1
2304i32 command::abt_NArgs(command::FieldId field, algo::strptr& out_dflt, bool* out_anon) {
2305 i32 retval = 1;
2306 switch (field) {
2307 case command_FieldId_target: { // $comment
2308 *out_anon = true;
2309 } break;
2310 case command_FieldId_in: { // $comment
2311 *out_anon = false;
2312 } break;
2313 case command_FieldId_out_dir: { // $comment
2314 *out_anon = false;
2315 } break;
2316 case command_FieldId_cfg: { // $comment
2317 *out_anon = false;
2318 } break;
2319 case command_FieldId_compiler: { // $comment
2320 *out_anon = false;
2321 } break;
2322 case command_FieldId_uname: { // $comment
2323 *out_anon = false;
2324 } break;
2325 case command_FieldId_arch: { // $comment
2326 *out_anon = false;
2327 } break;
2328 case command_FieldId_ood: { // $comment
2329 *out_anon = false;
2330 retval=0;
2331 out_dflt="Y";
2332 } break;
2333 case command_FieldId_list: { // bool: no argument required but value may be specified as ood:Y
2334 *out_anon = false;
2335 retval=0;
2336 out_dflt="Y";
2337 } break;
2338 case command_FieldId_listincl: { // bool: no argument required but value may be specified as list:Y
2339 *out_anon = false;
2340 retval=0;
2341 out_dflt="Y";
2342 } break;
2343 case command_FieldId_build: { // bool: no argument required but value may be specified as listincl:Y
2344 *out_anon = false;
2345 retval=0;
2346 out_dflt="Y";
2347 } break;
2348 case command_FieldId_preproc: { // bool: no argument required but value may be specified as build:Y
2349 *out_anon = false;
2350 retval=0;
2351 out_dflt="Y";
2352 } break;
2353 case command_FieldId_clean: { // bool: no argument required but value may be specified as preproc:Y
2354 *out_anon = false;
2355 retval=0;
2356 out_dflt="Y";
2357 } break;
2358 case command_FieldId_dry_run: { // bool: no argument required but value may be specified as clean:Y
2359 *out_anon = false;
2360 retval=0;
2361 out_dflt="Y";
2362 } break;
2363 case command_FieldId_maxjobs: { // bool: no argument required but value may be specified as dry_run:Y
2364 *out_anon = false;
2365 } break;
2366 case command_FieldId_printcmd: { // bool: no argument required but value may be specified as dry_run:Y
2367 *out_anon = false;
2368 retval=0;
2369 out_dflt="Y";
2370 } break;
2371 case command_FieldId_force: { // bool: no argument required but value may be specified as printcmd:Y
2372 *out_anon = false;
2373 retval=0;
2374 out_dflt="Y";
2375 } break;
2376 case command_FieldId_install: { // bool: no argument required but value may be specified as force:Y
2377 *out_anon = false;
2378 retval=0;
2379 out_dflt="Y";
2380 } break;
2381 case command_FieldId_coverity: { // bool: no argument required but value may be specified as install:Y
2382 *out_anon = false;
2383 retval=0;
2384 out_dflt="Y";
2385 } break;
2386 case command_FieldId_package: { // bool: no argument required but value may be specified as coverity:Y
2387 *out_anon = false;
2388 } break;
2389 case command_FieldId_maxerr: { // bool: no argument required but value may be specified as coverity:Y
2390 *out_anon = false;
2391 } break;
2392 case command_FieldId_disas: { // bool: no argument required but value may be specified as coverity:Y
2393 *out_anon = false;
2394 } break;
2395 case command_FieldId_report: { // bool: no argument required but value may be specified as coverity:Y
2396 *out_anon = false;
2397 retval=0;
2398 out_dflt="Y";
2399 } break;
2400 case command_FieldId_jcdb: { // bool: no argument required but value may be specified as report:Y
2401 *out_anon = false;
2402 } break;
2403 case command_FieldId_cache: { // bool: no argument required but value may be specified as report:Y
2404 *out_anon = false;
2405 } break;
2406 default:
2407 retval=-1; // unrecognized
2408 }
2409 return retval;
2410}
2411
2412// --- command.abt_md.readme.Print
2413// Print back to string
2414void command::readme_Print(command::abt_md& parent, algo::cstring &out) {
2415 Regx_Print(parent.readme, out);
2416}
2417
2418// --- command.abt_md.readme.ReadStrptrMaybe
2419// Read Regx from string
2420// Convert string to field. Return success value
2421bool command::readme_ReadStrptrMaybe(command::abt_md& parent, algo::strptr in) {
2422 bool retval = true;
2423 Regx_ReadSql(parent.readme, in, true);
2424 return retval;
2425}
2426
2427// --- command.abt_md.ns.Print
2428// Print back to string
2429void command::ns_Print(command::abt_md& parent, algo::cstring &out) {
2430 Regx_Print(parent.ns, out);
2431}
2432
2433// --- command.abt_md.ns.ReadStrptrMaybe
2434// Read Regx from string
2435// Convert string to field. Return success value
2436bool command::ns_ReadStrptrMaybe(command::abt_md& parent, algo::strptr in) {
2437 bool retval = true;
2438 Regx_ReadSql(parent.ns, in, true);
2439 return retval;
2440}
2441
2442// --- command.abt_md.section.Print
2443// Print back to string
2444void command::section_Print(command::abt_md& parent, algo::cstring &out) {
2445 Regx_Print(parent.section, out);
2446}
2447
2448// --- command.abt_md.section.ReadStrptrMaybe
2449// Read Regx from string
2450// Convert string to field. Return success value
2451bool command::section_ReadStrptrMaybe(command::abt_md& parent, algo::strptr in) {
2452 bool retval = true;
2453 Regx_ReadSql(parent.section, in, true);
2454 return retval;
2455}
2456
2457// --- command.abt_md..ReadFieldMaybe
2458bool command::abt_md_ReadFieldMaybe(command::abt_md& parent, algo::strptr field, algo::strptr strval) {
2459 bool retval = true;
2460 command::FieldId field_id;
2461 (void)value_SetStrptrMaybe(field_id,field);
2462 switch(field_id) {
2463 case command_FieldId_in: {
2464 retval = algo::cstring_ReadStrptrMaybe(parent.in, strval);
2465 break;
2466 }
2467 case command_FieldId_readme: {
2468 retval = readme_ReadStrptrMaybe(parent, strval);
2469 break;
2470 }
2471 case command_FieldId_ns: {
2472 retval = ns_ReadStrptrMaybe(parent, strval);
2473 break;
2474 }
2475 case command_FieldId_section: {
2476 retval = section_ReadStrptrMaybe(parent, strval);
2477 break;
2478 }
2479 case command_FieldId_update: {
2480 retval = bool_ReadStrptrMaybe(parent.update, strval);
2481 break;
2482 }
2483 case command_FieldId_check: {
2484 retval = bool_ReadStrptrMaybe(parent.check, strval);
2485 break;
2486 }
2487 case command_FieldId_link: {
2488 retval = bool_ReadStrptrMaybe(parent.link, strval);
2489 break;
2490 }
2491 case command_FieldId_anchor: {
2492 retval = bool_ReadStrptrMaybe(parent.anchor, strval);
2493 break;
2494 }
2495 case command_FieldId_print: {
2496 retval = bool_ReadStrptrMaybe(parent.print, strval);
2497 break;
2498 }
2499 case command_FieldId_dry_run: {
2500 retval = bool_ReadStrptrMaybe(parent.dry_run, strval);
2501 break;
2502 }
2503 default: break;
2504 }
2505 if (!retval) {
2506 algo_lib::AppendErrtext("attr",field);
2507 }
2508 return retval;
2509}
2510
2511// --- command.abt_md..ReadTupleMaybe
2512// Read fields of command::abt_md from attributes of ascii tuple TUPLE
2513bool command::abt_md_ReadTupleMaybe(command::abt_md &parent, algo::Tuple &tuple) {
2514 bool retval = true;
2515 int anon_idx = 0;
2516 ind_beg(algo::Tuple_attrs_curs,attr,tuple) {
2517 if (ch_N(attr.name) == 0) {
2518 attr.name = abt_md_GetAnon(parent, anon_idx++);
2519 }
2520 retval = abt_md_ReadFieldMaybe(parent, attr.name, attr.value);
2521 if (!retval) {
2522 break;
2523 }
2524 }ind_end;
2525 return retval;
2526}
2527
2528// --- command.abt_md..Init
2529// Set all fields to initial values.
2530void command::abt_md_Init(command::abt_md& parent) {
2531 parent.in = algo::strptr("data");
2532 Regx_ReadSql(parent.readme, "%", true);
2533 Regx_ReadSql(parent.ns, "", true);
2534 Regx_ReadSql(parent.section, "%", true);
2535 parent.update = bool(true);
2536 parent.check = bool(false);
2537 parent.link = bool(false);
2538 parent.anchor = bool(false);
2539 parent.print = bool(false);
2540 parent.dry_run = bool(false);
2541}
2542
2543// --- command.abt_md..ToCmdline
2544// Convenience function that returns a full command line
2545// Assume command is in a directory called bin
2546tempstr command::abt_md_ToCmdline(command::abt_md& row) {
2547 tempstr ret;
2548 ret << "bin/abt_md ";
2549 abt_md_PrintArgv(row, ret);
2550 // inherit less intense verbose, debug options
2551 for (int i = 1; i < algo_lib::_db.cmdline.verbose; i++) {
2552 ret << " -verbose";
2553 }
2554 for (int i = 1; i < algo_lib::_db.cmdline.debug; i++) {
2555 ret << " -debug";
2556 }
2557 return ret;
2558}
2559
2560// --- command.abt_md..PrintArgv
2561// print string representation of ROW to string STR
2562// cfmt:command.abt_md.Argv printfmt:Tuple
2563void command::abt_md_PrintArgv(command::abt_md& row, algo::cstring& str) {
2564 algo::tempstr temp;
2565 (void)temp;
2566 (void)str;
2567 if (!(row.in == "data")) {
2568 ch_RemoveAll(temp);
2569 cstring_Print(row.in, temp);
2570 str << " -in:";
2571 strptr_PrintBash(temp,str);
2572 }
2573 ch_RemoveAll(temp);
2574 command::readme_Print(const_cast<command::abt_md&>(row), temp);
2575 str << " -readme:";
2576 strptr_PrintBash(temp,str);
2577 if (!(row.ns.expr == "")) {
2578 ch_RemoveAll(temp);
2579 command::ns_Print(const_cast<command::abt_md&>(row), temp);
2580 str << " -ns:";
2581 strptr_PrintBash(temp,str);
2582 }
2583 ch_RemoveAll(temp);
2584 command::section_Print(const_cast<command::abt_md&>(row), temp);
2585 str << " -section:";
2586 strptr_PrintBash(temp,str);
2587 if (!(row.update == true)) {
2588 ch_RemoveAll(temp);
2589 bool_Print(row.update, temp);
2590 str << " -update:";
2591 strptr_PrintBash(temp,str);
2592 }
2593 if (!(row.check == false)) {
2594 ch_RemoveAll(temp);
2595 bool_Print(row.check, temp);
2596 str << " -check:";
2597 strptr_PrintBash(temp,str);
2598 }
2599 if (!(row.link == false)) {
2600 ch_RemoveAll(temp);
2601 bool_Print(row.link, temp);
2602 str << " -link:";
2603 strptr_PrintBash(temp,str);
2604 }
2605 if (!(row.anchor == false)) {
2606 ch_RemoveAll(temp);
2607 bool_Print(row.anchor, temp);
2608 str << " -anchor:";
2609 strptr_PrintBash(temp,str);
2610 }
2611 if (!(row.print == false)) {
2612 ch_RemoveAll(temp);
2613 bool_Print(row.print, temp);
2614 str << " -print:";
2615 strptr_PrintBash(temp,str);
2616 }
2617 if (!(row.dry_run == false)) {
2618 ch_RemoveAll(temp);
2619 bool_Print(row.dry_run, temp);
2620 str << " -dry_run:";
2621 strptr_PrintBash(temp,str);
2622 }
2623}
2624
2625// --- command.abt_md..GetAnon
2626algo::strptr command::abt_md_GetAnon(command::abt_md &parent, i32 idx) {
2627 (void)parent;//only to avoid -Wunused-parameter
2628 switch(idx) {
2629 case(0): return strptr("readme", 6);
2630 case(1): return strptr("section", 7);
2631 default: return algo::strptr();
2632 }
2633}
2634
2635// --- command.abt_md..NArgs
2636// Used with command lines
2637// Return # of command-line arguments that must follow this argument
2638// If FIELD is invalid, return -1
2639i32 command::abt_md_NArgs(command::FieldId field, algo::strptr& out_dflt, bool* out_anon) {
2640 i32 retval = 1;
2641 switch (field) {
2642 case command_FieldId_in: { // $comment
2643 *out_anon = false;
2644 } break;
2645 case command_FieldId_readme: { // $comment
2646 *out_anon = true;
2647 } break;
2648 case command_FieldId_ns: { // $comment
2649 *out_anon = false;
2650 } break;
2651 case command_FieldId_section: { // $comment
2652 *out_anon = true;
2653 } break;
2654 case command_FieldId_update: { // $comment
2655 *out_anon = false;
2656 retval=0;
2657 out_dflt="Y";
2658 } break;
2659 case command_FieldId_check: { // bool: no argument required but value may be specified as update:Y
2660 *out_anon = false;
2661 retval=0;
2662 out_dflt="Y";
2663 } break;
2664 case command_FieldId_link: { // bool: no argument required but value may be specified as check:Y
2665 *out_anon = false;
2666 retval=0;
2667 out_dflt="Y";
2668 } break;
2669 case command_FieldId_anchor: { // bool: no argument required but value may be specified as link:Y
2670 *out_anon = false;
2671 retval=0;
2672 out_dflt="Y";
2673 } break;
2674 case command_FieldId_print: { // bool: no argument required but value may be specified as anchor:Y
2675 *out_anon = false;
2676 retval=0;
2677 out_dflt="Y";
2678 } break;
2679 case command_FieldId_dry_run: { // bool: no argument required but value may be specified as print:Y
2680 *out_anon = false;
2681 retval=0;
2682 out_dflt="Y";
2683 } break;
2684 default:
2685 retval=-1; // unrecognized
2686 }
2687 return retval;
2688}
2689
2690// --- command.abt_md_proc.abt_md.Start
2691// Start subprocess
2692// If subprocess already running, do nothing. Otherwise, start it
2693int command::abt_md_Start(command::abt_md_proc& parent) {
2694 int retval = 0;
2695 if (parent.pid == 0) {
2696 verblog(abt_md_ToCmdline(parent)); // maybe print command
2697#ifdef WIN32
2698 algo_lib::ResolveExecFname(parent.path);
2699 tempstr cmdline(abt_md_ToCmdline(parent));
2700 parent.pid = dospawn(Zeroterm(parent.path),Zeroterm(cmdline),parent.timeout,parent.fstdin,parent.fstdout,parent.fstderr);
2701#else
2702 parent.pid = fork();
2703 if (parent.pid == 0) { // child
2704 algo_lib::DieWithParent();
2705 if (parent.timeout > 0) {
2706 alarm(parent.timeout);
2707 }
2708 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstdin , 0);
2709 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstdout, 1);
2710 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstderr, 2);
2711 if (retval==0) retval= abt_md_Execv(parent);
2712 if (retval != 0) { // if start fails, print error
2713 int err=errno;
2714 prerr("command.abt_md_execv"
2715 <<Keyval("errno",err)
2716 <<Keyval("errstr",strerror(err))
2717 <<Keyval("comment","Execv failed"));
2718 }
2719 _exit(127); // if failed to start, exit anyway
2720 } else if (parent.pid == -1) {
2721 retval = errno; // failed to fork
2722 }
2723#endif
2724 }
2725 parent.status = parent.pid > 0 ? 0 : -1; // if didn't start, set error status
2726 return retval;
2727}
2728
2729// --- command.abt_md_proc.abt_md.StartRead
2730// Start subprocess & Read output
2731algo::Fildes command::abt_md_StartRead(command::abt_md_proc& parent, algo_lib::FFildes &read) {
2732 int pipefd[2];
2733 int rc=pipe(pipefd);
2734 (void)rc;
2735 read.fd.value = pipefd[0];
2736 parent.fstdout << ">&" << pipefd[1];
2737 abt_md_Start(parent);
2738 (void)close(pipefd[1]);
2739 return read.fd;
2740}
2741
2742// --- command.abt_md_proc.abt_md.Kill
2743// Kill subprocess and wait
2744void command::abt_md_Kill(command::abt_md_proc& parent) {
2745 if (parent.pid != 0) {
2746 kill(parent.pid,9);
2747 abt_md_Wait(parent);
2748 }
2749}
2750
2751// --- command.abt_md_proc.abt_md.Wait
2752// Wait for subprocess to return
2753void command::abt_md_Wait(command::abt_md_proc& parent) {
2754 if (parent.pid > 0) {
2755 int wait_flags = 0;
2756 int wait_status = 0;
2757 int rc = -1;
2758 do {
2759 // really wait for subprocess to exit
2760 rc = waitpid(parent.pid,&wait_status,wait_flags);
2761 } while (rc==-1 && errno==EINTR);
2762 if (rc == parent.pid) {
2763 parent.status = wait_status;
2764 parent.pid = 0;
2765 }
2766 }
2767}
2768
2769// --- command.abt_md_proc.abt_md.Exec
2770// Start + Wait
2771// Execute subprocess and return exit code
2772int command::abt_md_Exec(command::abt_md_proc& parent) {
2773 abt_md_Start(parent);
2774 abt_md_Wait(parent);
2775 return parent.status;
2776}
2777
2778// --- command.abt_md_proc.abt_md.ExecX
2779// Start + Wait, throw exception on error
2780// Execute subprocess; throw human-readable exception on error
2781void command::abt_md_ExecX(command::abt_md_proc& parent) {
2782 int rc = abt_md_Exec(parent);
2783 vrfy(rc==0, tempstr() << "algo_lib.exec" << Keyval("cmd",abt_md_ToCmdline(parent))
2784 << Keyval("comment",algo::DescribeWaitStatus(parent.status)));
2785}
2786
2787// --- command.abt_md_proc.abt_md.Execv
2788// Call execv()
2789// Call execv with specified parameters
2790int command::abt_md_Execv(command::abt_md_proc& parent) {
2791 int ret = 0;
2792 algo::StringAry args;
2793 abt_md_ToArgv(parent, args);
2794 char **argv = (char**)alloca((ary_N(args)+1)*sizeof(*argv));
2795 ind_beg(algo::StringAry_ary_curs,arg,args) {
2796 argv[ind_curs(arg).index] = Zeroterm(arg);
2797 }ind_end;
2798 argv[ary_N(args)] = NULL;
2799 // if parent.path is relative, search for it in PATH
2800 algo_lib::ResolveExecFname(parent.path);
2801 ret = execv(Zeroterm(parent.path),argv);
2802 return ret;
2803}
2804
2805// --- command.abt_md_proc.abt_md.ToCmdline
2806algo::tempstr command::abt_md_ToCmdline(command::abt_md_proc& parent) {
2807 algo::tempstr retval;
2808 retval << parent.path << " ";
2809 command::abt_md_PrintArgv(parent.cmd,retval);
2810 if (ch_N(parent.fstdin)) {
2811 retval << " " << parent.fstdin;
2812 }
2813 if (ch_N(parent.fstdout)) {
2814 retval << " " << parent.fstdout;
2815 }
2816 if (ch_N(parent.fstderr)) {
2817 retval << " 2" << parent.fstderr;
2818 }
2819 return retval;
2820}
2821
2822// --- command.abt_md_proc.abt_md.ToArgv
2823// Form array from the command line
2824void command::abt_md_ToArgv(command::abt_md_proc& parent, algo::StringAry& args) {
2825 ary_RemoveAll(args);
2826 ary_Alloc(args) << parent.path;
2827
2828 if (parent.cmd.in != "data") {
2829 cstring *arg = &ary_Alloc(args);
2830 *arg << "-in:";
2831 cstring_Print(parent.cmd.in, *arg);
2832 }
2833
2834 if (parent.cmd.readme.expr != "%") {
2835 cstring *arg = &ary_Alloc(args);
2836 *arg << "-readme:";
2837 command::readme_Print(parent.cmd, *arg);
2838 }
2839
2840 if (parent.cmd.ns.expr != "") {
2841 cstring *arg = &ary_Alloc(args);
2842 *arg << "-ns:";
2843 command::ns_Print(parent.cmd, *arg);
2844 }
2845
2846 if (parent.cmd.section.expr != "%") {
2847 cstring *arg = &ary_Alloc(args);
2848 *arg << "-section:";
2849 command::section_Print(parent.cmd, *arg);
2850 }
2851
2852 if (parent.cmd.update != true) {
2853 cstring *arg = &ary_Alloc(args);
2854 *arg << "-update:";
2855 bool_Print(parent.cmd.update, *arg);
2856 }
2857
2858 if (parent.cmd.check != false) {
2859 cstring *arg = &ary_Alloc(args);
2860 *arg << "-check:";
2861 bool_Print(parent.cmd.check, *arg);
2862 }
2863
2864 if (parent.cmd.link != false) {
2865 cstring *arg = &ary_Alloc(args);
2866 *arg << "-link:";
2867 bool_Print(parent.cmd.link, *arg);
2868 }
2869
2870 if (parent.cmd.anchor != false) {
2871 cstring *arg = &ary_Alloc(args);
2872 *arg << "-anchor:";
2873 bool_Print(parent.cmd.anchor, *arg);
2874 }
2875
2876 if (parent.cmd.print != false) {
2877 cstring *arg = &ary_Alloc(args);
2878 *arg << "-print:";
2879 bool_Print(parent.cmd.print, *arg);
2880 }
2881
2882 if (parent.cmd.dry_run != false) {
2883 cstring *arg = &ary_Alloc(args);
2884 *arg << "-dry_run:";
2885 bool_Print(parent.cmd.dry_run, *arg);
2886 }
2887 for (int i=1; i < algo_lib::_db.cmdline.verbose; ++i) {
2888 ary_Alloc(args) << "-verbose";
2889 }
2890}
2891
2892// --- command.abt_md_proc..Uninit
2893void command::abt_md_proc_Uninit(command::abt_md_proc& parent) {
2894 command::abt_md_proc &row = parent; (void)row;
2895
2896 // command.abt_md_proc.abt_md.Uninit (Exec) //
2897 abt_md_Kill(parent); // kill child, ensure forward progress
2898}
2899
2900// --- command.abt_proc.abt.Start
2901// Start subprocess
2902// If subprocess already running, do nothing. Otherwise, start it
2903int command::abt_Start(command::abt_proc& parent) {
2904 int retval = 0;
2905 if (parent.pid == 0) {
2906 verblog(abt_ToCmdline(parent)); // maybe print command
2907#ifdef WIN32
2908 algo_lib::ResolveExecFname(parent.path);
2909 tempstr cmdline(abt_ToCmdline(parent));
2910 parent.pid = dospawn(Zeroterm(parent.path),Zeroterm(cmdline),parent.timeout,parent.fstdin,parent.fstdout,parent.fstderr);
2911#else
2912 parent.pid = fork();
2913 if (parent.pid == 0) { // child
2914 algo_lib::DieWithParent();
2915 if (parent.timeout > 0) {
2916 alarm(parent.timeout);
2917 }
2918 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstdin , 0);
2919 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstdout, 1);
2920 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstderr, 2);
2921 if (retval==0) retval= abt_Execv(parent);
2922 if (retval != 0) { // if start fails, print error
2923 int err=errno;
2924 prerr("command.abt_execv"
2925 <<Keyval("errno",err)
2926 <<Keyval("errstr",strerror(err))
2927 <<Keyval("comment","Execv failed"));
2928 }
2929 _exit(127); // if failed to start, exit anyway
2930 } else if (parent.pid == -1) {
2931 retval = errno; // failed to fork
2932 }
2933#endif
2934 }
2935 parent.status = parent.pid > 0 ? 0 : -1; // if didn't start, set error status
2936 return retval;
2937}
2938
2939// --- command.abt_proc.abt.StartRead
2940// Start subprocess & Read output
2941algo::Fildes command::abt_StartRead(command::abt_proc& parent, algo_lib::FFildes &read) {
2942 int pipefd[2];
2943 int rc=pipe(pipefd);
2944 (void)rc;
2945 read.fd.value = pipefd[0];
2946 parent.fstdout << ">&" << pipefd[1];
2947 abt_Start(parent);
2948 (void)close(pipefd[1]);
2949 return read.fd;
2950}
2951
2952// --- command.abt_proc.abt.Kill
2953// Kill subprocess and wait
2954void command::abt_Kill(command::abt_proc& parent) {
2955 if (parent.pid != 0) {
2956 kill(parent.pid,9);
2957 abt_Wait(parent);
2958 }
2959}
2960
2961// --- command.abt_proc.abt.Wait
2962// Wait for subprocess to return
2963void command::abt_Wait(command::abt_proc& parent) {
2964 if (parent.pid > 0) {
2965 int wait_flags = 0;
2966 int wait_status = 0;
2967 int rc = -1;
2968 do {
2969 // really wait for subprocess to exit
2970 rc = waitpid(parent.pid,&wait_status,wait_flags);
2971 } while (rc==-1 && errno==EINTR);
2972 if (rc == parent.pid) {
2973 parent.status = wait_status;
2974 parent.pid = 0;
2975 }
2976 }
2977}
2978
2979// --- command.abt_proc.abt.Exec
2980// Start + Wait
2981// Execute subprocess and return exit code
2982int command::abt_Exec(command::abt_proc& parent) {
2983 abt_Start(parent);
2984 abt_Wait(parent);
2985 return parent.status;
2986}
2987
2988// --- command.abt_proc.abt.ExecX
2989// Start + Wait, throw exception on error
2990// Execute subprocess; throw human-readable exception on error
2991void command::abt_ExecX(command::abt_proc& parent) {
2992 int rc = abt_Exec(parent);
2993 vrfy(rc==0, tempstr() << "algo_lib.exec" << Keyval("cmd",abt_ToCmdline(parent))
2994 << Keyval("comment",algo::DescribeWaitStatus(parent.status)));
2995}
2996
2997// --- command.abt_proc.abt.Execv
2998// Call execv()
2999// Call execv with specified parameters
3000int command::abt_Execv(command::abt_proc& parent) {
3001 int ret = 0;
3002 algo::StringAry args;
3003 abt_ToArgv(parent, args);
3004 char **argv = (char**)alloca((ary_N(args)+1)*sizeof(*argv));
3005 ind_beg(algo::StringAry_ary_curs,arg,args) {
3006 argv[ind_curs(arg).index] = Zeroterm(arg);
3007 }ind_end;
3008 argv[ary_N(args)] = NULL;
3009 // if parent.path is relative, search for it in PATH
3010 algo_lib::ResolveExecFname(parent.path);
3011 ret = execv(Zeroterm(parent.path),argv);
3012 return ret;
3013}
3014
3015// --- command.abt_proc.abt.ToCmdline
3016algo::tempstr command::abt_ToCmdline(command::abt_proc& parent) {
3017 algo::tempstr retval;
3018 retval << parent.path << " ";
3019 command::abt_PrintArgv(parent.cmd,retval);
3020 if (ch_N(parent.fstdin)) {
3021 retval << " " << parent.fstdin;
3022 }
3023 if (ch_N(parent.fstdout)) {
3024 retval << " " << parent.fstdout;
3025 }
3026 if (ch_N(parent.fstderr)) {
3027 retval << " 2" << parent.fstderr;
3028 }
3029 return retval;
3030}
3031
3032// --- command.abt_proc.abt.ToArgv
3033// Form array from the command line
3034void command::abt_ToArgv(command::abt_proc& parent, algo::StringAry& args) {
3035 ary_RemoveAll(args);
3036 ary_Alloc(args) << parent.path;
3037
3038 if (parent.cmd.target.expr != "") {
3039 cstring *arg = &ary_Alloc(args);
3040 *arg << "-target:";
3041 command::target_Print(parent.cmd, *arg);
3042 }
3043
3044 if (parent.cmd.in != "data") {
3045 cstring *arg = &ary_Alloc(args);
3046 *arg << "-in:";
3047 cstring_Print(parent.cmd.in, *arg);
3048 }
3049
3050 if (parent.cmd.out_dir != "") {
3051 cstring *arg = &ary_Alloc(args);
3052 *arg << "-out_dir:";
3053 cstring_Print(parent.cmd.out_dir, *arg);
3054 }
3055
3056 if (parent.cmd.cfg != "") {
3057 cstring *arg = &ary_Alloc(args);
3058 *arg << "-cfg:";
3059 Smallstr50_Print(parent.cmd.cfg, *arg);
3060 }
3061
3062 if (parent.cmd.compiler != "") {
3063 cstring *arg = &ary_Alloc(args);
3064 *arg << "-compiler:";
3065 Smallstr50_Print(parent.cmd.compiler, *arg);
3066 }
3067
3068 if (parent.cmd.uname != "") {
3069 cstring *arg = &ary_Alloc(args);
3070 *arg << "-uname:";
3071 Smallstr50_Print(parent.cmd.uname, *arg);
3072 }
3073
3074 if (parent.cmd.arch != "") {
3075 cstring *arg = &ary_Alloc(args);
3076 *arg << "-arch:";
3077 Smallstr50_Print(parent.cmd.arch, *arg);
3078 }
3079
3080 if (parent.cmd.ood != false) {
3081 cstring *arg = &ary_Alloc(args);
3082 *arg << "-ood:";
3083 bool_Print(parent.cmd.ood, *arg);
3084 }
3085
3086 if (parent.cmd.list != false) {
3087 cstring *arg = &ary_Alloc(args);
3088 *arg << "-list:";
3089 bool_Print(parent.cmd.list, *arg);
3090 }
3091
3092 if (parent.cmd.listincl != false) {
3093 cstring *arg = &ary_Alloc(args);
3094 *arg << "-listincl:";
3095 bool_Print(parent.cmd.listincl, *arg);
3096 }
3097
3098 if (parent.cmd.build != false) {
3099 cstring *arg = &ary_Alloc(args);
3100 *arg << "-build:";
3101 bool_Print(parent.cmd.build, *arg);
3102 }
3103
3104 if (parent.cmd.preproc != false) {
3105 cstring *arg = &ary_Alloc(args);
3106 *arg << "-preproc:";
3107 bool_Print(parent.cmd.preproc, *arg);
3108 }
3109
3110 if (parent.cmd.clean != false) {
3111 cstring *arg = &ary_Alloc(args);
3112 *arg << "-clean:";
3113 bool_Print(parent.cmd.clean, *arg);
3114 }
3115
3116 if (parent.cmd.dry_run != false) {
3117 cstring *arg = &ary_Alloc(args);
3118 *arg << "-dry_run:";
3119 bool_Print(parent.cmd.dry_run, *arg);
3120 }
3121
3122 if (parent.cmd.maxjobs != 0) {
3123 cstring *arg = &ary_Alloc(args);
3124 *arg << "-maxjobs:";
3125 i32_Print(parent.cmd.maxjobs, *arg);
3126 }
3127
3128 if (parent.cmd.printcmd != false) {
3129 cstring *arg = &ary_Alloc(args);
3130 *arg << "-printcmd:";
3131 bool_Print(parent.cmd.printcmd, *arg);
3132 }
3133
3134 if (parent.cmd.force != false) {
3135 cstring *arg = &ary_Alloc(args);
3136 *arg << "-force:";
3137 bool_Print(parent.cmd.force, *arg);
3138 }
3139
3140 if (parent.cmd.install != false) {
3141 cstring *arg = &ary_Alloc(args);
3142 *arg << "-install:";
3143 bool_Print(parent.cmd.install, *arg);
3144 }
3145
3146 if (parent.cmd.coverity != false) {
3147 cstring *arg = &ary_Alloc(args);
3148 *arg << "-coverity:";
3149 bool_Print(parent.cmd.coverity, *arg);
3150 }
3151
3152 if (parent.cmd.package != "") {
3153 cstring *arg = &ary_Alloc(args);
3154 *arg << "-package:";
3155 cstring_Print(parent.cmd.package, *arg);
3156 }
3157
3158 if (parent.cmd.maxerr != 100) {
3159 cstring *arg = &ary_Alloc(args);
3160 *arg << "-maxerr:";
3161 u32_Print(parent.cmd.maxerr, *arg);
3162 }
3163
3164 if (parent.cmd.disas.expr != "") {
3165 cstring *arg = &ary_Alloc(args);
3166 *arg << "-disas:";
3167 command::disas_Print(parent.cmd, *arg);
3168 }
3169
3170 if (parent.cmd.report != true) {
3171 cstring *arg = &ary_Alloc(args);
3172 *arg << "-report:";
3173 bool_Print(parent.cmd.report, *arg);
3174 }
3175
3176 if (parent.cmd.jcdb != "") {
3177 cstring *arg = &ary_Alloc(args);
3178 *arg << "-jcdb:";
3179 cstring_Print(parent.cmd.jcdb, *arg);
3180 }
3181
3182 if (parent.cmd.cache != 0) {
3183 cstring *arg = &ary_Alloc(args);
3184 *arg << "-cache:";
3185 command::cache_Print(parent.cmd, *arg);
3186 }
3187 for (int i=1; i < algo_lib::_db.cmdline.verbose; ++i) {
3188 ary_Alloc(args) << "-verbose";
3189 }
3190}
3191
3192// --- command.abt_proc..Uninit
3193void command::abt_proc_Uninit(command::abt_proc& parent) {
3194 command::abt_proc &row = parent; (void)row;
3195
3196 // command.abt_proc.abt.Uninit (Exec) //
3197 abt_Kill(parent); // kill child, ensure forward progress
3198}
3199
3200// --- command.acr.where.Addary
3201// Reserve space (this may move memory). Insert N element at the end.
3202// Return aryptr to newly inserted block.
3203// If the RHS argument aliases the array (refers to the same memory), exit program with fatal error.
3204algo::aryptr<algo::cstring> command::where_Addary(command::acr& parent, algo::aryptr<algo::cstring> rhs) {
3205 bool overlaps = rhs.n_elems>0 && rhs.elems >= parent.where_elems && rhs.elems < parent.where_elems + parent.where_max;
3206 if (UNLIKELY(overlaps)) {
3207 FatalErrorExit("command.tary_alias field:command.acr.where comment:'alias error: sub-array is being appended to the whole'");
3208 }
3209 int nnew = rhs.n_elems;
3210 where_Reserve(parent, nnew); // reserve space
3211 int at = parent.where_n;
3212 for (int i = 0; i < nnew; i++) {
3213 new (parent.where_elems + at + i) algo::cstring(rhs[i]);
3214 parent.where_n++;
3215 }
3216 return algo::aryptr<algo::cstring>(parent.where_elems + at, nnew);
3217}
3218
3219// --- command.acr.where.Alloc
3220// Reserve space. Insert element at the end
3221// The new element is initialized to a default value
3222algo::cstring& command::where_Alloc(command::acr& parent) {
3223 where_Reserve(parent, 1);
3224 int n = parent.where_n;
3225 int at = n;
3226 algo::cstring *elems = parent.where_elems;
3227 new (elems + at) algo::cstring(); // construct new element, default initializer
3228 parent.where_n = n+1;
3229 return elems[at];
3230}
3231
3232// --- command.acr.where.AllocAt
3233// Reserve space for new element, reallocating the array if necessary
3234// Insert new element at specified index. Index must be in range or a fatal error occurs.
3235algo::cstring& command::where_AllocAt(command::acr& parent, int at) {
3236 where_Reserve(parent, 1);
3237 int n = parent.where_n;
3238 if (UNLIKELY(u64(at) >= u64(n+1))) {
3239 FatalErrorExit("command.bad_alloc_at field:command.acr.where comment:'index out of range'");
3240 }
3241 algo::cstring *elems = parent.where_elems;
3242 memmove(elems + at + 1, elems + at, (n - at) * sizeof(algo::cstring));
3243 new (elems + at) algo::cstring(); // construct element, default initializer
3244 parent.where_n = n+1;
3245 return elems[at];
3246}
3247
3248// --- command.acr.where.AllocN
3249// Reserve space. Insert N elements at the end of the array, return pointer to array
3250algo::aryptr<algo::cstring> command::where_AllocN(command::acr& parent, int n_elems) {
3251 where_Reserve(parent, n_elems);
3252 int old_n = parent.where_n;
3253 int new_n = old_n + n_elems;
3254 algo::cstring *elems = parent.where_elems;
3255 for (int i = old_n; i < new_n; i++) {
3256 new (elems + i) algo::cstring(); // construct new element, default initialize
3257 }
3258 parent.where_n = new_n;
3259 return algo::aryptr<algo::cstring>(elems + old_n, n_elems);
3260}
3261
3262// --- command.acr.where.Remove
3263// Remove item by index. If index outside of range, do nothing.
3264void command::where_Remove(command::acr& parent, u32 i) {
3265 u32 lim = parent.where_n;
3266 algo::cstring *elems = parent.where_elems;
3267 if (i < lim) {
3268 elems[i].~cstring(); // destroy element
3269 memmove(elems + i, elems + (i + 1), sizeof(algo::cstring) * (lim - (i + 1)));
3270 parent.where_n = lim - 1;
3271 }
3272}
3273
3274// --- command.acr.where.RemoveAll
3275void command::where_RemoveAll(command::acr& parent) {
3276 u32 n = parent.where_n;
3277 while (n > 0) {
3278 n -= 1;
3279 parent.where_elems[n].~cstring();
3280 parent.where_n = n;
3281 }
3282}
3283
3284// --- command.acr.where.RemoveLast
3285// Delete last element of array. Do nothing if array is empty.
3286void command::where_RemoveLast(command::acr& parent) {
3287 u64 n = parent.where_n;
3288 if (n > 0) {
3289 n -= 1;
3290 where_qFind(parent, u64(n)).~cstring();
3291 parent.where_n = n;
3292 }
3293}
3294
3295// --- command.acr.where.AbsReserve
3296// Make sure N elements fit in array. Process dies if out of memory
3297void command::where_AbsReserve(command::acr& parent, int n) {
3298 u32 old_max = parent.where_max;
3299 if (n > i32(old_max)) {
3300 u32 new_max = i32_Max(i32_Max(old_max * 2, n), 4);
3301 void *new_mem = algo_lib::malloc_ReallocMem(parent.where_elems, old_max * sizeof(algo::cstring), new_max * sizeof(algo::cstring));
3302 if (UNLIKELY(!new_mem)) {
3303 FatalErrorExit("command.tary_nomem field:command.acr.where comment:'out of memory'");
3304 }
3305 parent.where_elems = (algo::cstring*)new_mem;
3306 parent.where_max = new_max;
3307 }
3308}
3309
3310// --- command.acr.where.Setary
3311// Copy contents of RHS to PARENT.
3312void command::where_Setary(command::acr& parent, command::acr &rhs) {
3313 where_RemoveAll(parent);
3314 int nnew = rhs.where_n;
3315 where_Reserve(parent, nnew); // reserve space
3316 for (int i = 0; i < nnew; i++) { // copy elements over
3317 new (parent.where_elems + i) algo::cstring(where_qFind(rhs, i));
3318 parent.where_n = i + 1;
3319 }
3320}
3321
3322// --- command.acr.where.Setary2
3323// Copy specified array into where, discarding previous contents.
3324// If the RHS argument aliases the array (refers to the same memory), throw exception.
3325void command::where_Setary(command::acr& parent, const algo::aryptr<algo::cstring> &rhs) {
3326 where_RemoveAll(parent);
3327 where_Addary(parent, rhs);
3328}
3329
3330// --- command.acr.where.AllocNVal
3331// Reserve space. Insert N elements at the end of the array, return pointer to array
3332algo::aryptr<algo::cstring> command::where_AllocNVal(command::acr& parent, int n_elems, const algo::cstring& val) {
3333 where_Reserve(parent, n_elems);
3334 int old_n = parent.where_n;
3335 int new_n = old_n + n_elems;
3336 algo::cstring *elems = parent.where_elems;
3337 for (int i = old_n; i < new_n; i++) {
3338 new (elems + i) algo::cstring(val);
3339 }
3340 parent.where_n = new_n;
3341 return algo::aryptr<algo::cstring>(elems + old_n, n_elems);
3342}
3343
3344// --- command.acr.where.ReadStrptrMaybe
3345// A single element is read from input string and appended to the array.
3346// If the string contains an error, the array is untouched.
3347// Function returns success value.
3348bool command::where_ReadStrptrMaybe(command::acr& parent, algo::strptr in_str) {
3349 bool retval = true;
3350 algo::cstring &elem = where_Alloc(parent);
3351 retval = algo::cstring_ReadStrptrMaybe(elem, in_str);
3352 if (!retval) {
3353 where_RemoveLast(parent);
3354 }
3355 return retval;
3356}
3357
3358// --- command.acr.field.Addary
3359// Reserve space (this may move memory). Insert N element at the end.
3360// Return aryptr to newly inserted block.
3361// If the RHS argument aliases the array (refers to the same memory), exit program with fatal error.
3362algo::aryptr<algo::cstring> command::field_Addary(command::acr& parent, algo::aryptr<algo::cstring> rhs) {
3363 bool overlaps = rhs.n_elems>0 && rhs.elems >= parent.field_elems && rhs.elems < parent.field_elems + parent.field_max;
3364 if (UNLIKELY(overlaps)) {
3365 FatalErrorExit("command.tary_alias field:command.acr.field comment:'alias error: sub-array is being appended to the whole'");
3366 }
3367 int nnew = rhs.n_elems;
3368 field_Reserve(parent, nnew); // reserve space
3369 int at = parent.field_n;
3370 for (int i = 0; i < nnew; i++) {
3371 new (parent.field_elems + at + i) algo::cstring(rhs[i]);
3372 parent.field_n++;
3373 }
3374 return algo::aryptr<algo::cstring>(parent.field_elems + at, nnew);
3375}
3376
3377// --- command.acr.field.Alloc
3378// Reserve space. Insert element at the end
3379// The new element is initialized to a default value
3380algo::cstring& command::field_Alloc(command::acr& parent) {
3381 field_Reserve(parent, 1);
3382 int n = parent.field_n;
3383 int at = n;
3384 algo::cstring *elems = parent.field_elems;
3385 new (elems + at) algo::cstring(); // construct new element, default initializer
3386 parent.field_n = n+1;
3387 return elems[at];
3388}
3389
3390// --- command.acr.field.AllocAt
3391// Reserve space for new element, reallocating the array if necessary
3392// Insert new element at specified index. Index must be in range or a fatal error occurs.
3393algo::cstring& command::field_AllocAt(command::acr& parent, int at) {
3394 field_Reserve(parent, 1);
3395 int n = parent.field_n;
3396 if (UNLIKELY(u64(at) >= u64(n+1))) {
3397 FatalErrorExit("command.bad_alloc_at field:command.acr.field comment:'index out of range'");
3398 }
3399 algo::cstring *elems = parent.field_elems;
3400 memmove(elems + at + 1, elems + at, (n - at) * sizeof(algo::cstring));
3401 new (elems + at) algo::cstring(); // construct element, default initializer
3402 parent.field_n = n+1;
3403 return elems[at];
3404}
3405
3406// --- command.acr.field.AllocN
3407// Reserve space. Insert N elements at the end of the array, return pointer to array
3408algo::aryptr<algo::cstring> command::field_AllocN(command::acr& parent, int n_elems) {
3409 field_Reserve(parent, n_elems);
3410 int old_n = parent.field_n;
3411 int new_n = old_n + n_elems;
3412 algo::cstring *elems = parent.field_elems;
3413 for (int i = old_n; i < new_n; i++) {
3414 new (elems + i) algo::cstring(); // construct new element, default initialize
3415 }
3416 parent.field_n = new_n;
3417 return algo::aryptr<algo::cstring>(elems + old_n, n_elems);
3418}
3419
3420// --- command.acr.field.Remove
3421// Remove item by index. If index outside of range, do nothing.
3422void command::field_Remove(command::acr& parent, u32 i) {
3423 u32 lim = parent.field_n;
3424 algo::cstring *elems = parent.field_elems;
3425 if (i < lim) {
3426 elems[i].~cstring(); // destroy element
3427 memmove(elems + i, elems + (i + 1), sizeof(algo::cstring) * (lim - (i + 1)));
3428 parent.field_n = lim - 1;
3429 }
3430}
3431
3432// --- command.acr.field.RemoveAll
3433void command::field_RemoveAll(command::acr& parent) {
3434 u32 n = parent.field_n;
3435 while (n > 0) {
3436 n -= 1;
3437 parent.field_elems[n].~cstring();
3438 parent.field_n = n;
3439 }
3440}
3441
3442// --- command.acr.field.RemoveLast
3443// Delete last element of array. Do nothing if array is empty.
3444void command::field_RemoveLast(command::acr& parent) {
3445 u64 n = parent.field_n;
3446 if (n > 0) {
3447 n -= 1;
3448 field_qFind(parent, u64(n)).~cstring();
3449 parent.field_n = n;
3450 }
3451}
3452
3453// --- command.acr.field.AbsReserve
3454// Make sure N elements fit in array. Process dies if out of memory
3455void command::field_AbsReserve(command::acr& parent, int n) {
3456 u32 old_max = parent.field_max;
3457 if (n > i32(old_max)) {
3458 u32 new_max = i32_Max(i32_Max(old_max * 2, n), 4);
3459 void *new_mem = algo_lib::malloc_ReallocMem(parent.field_elems, old_max * sizeof(algo::cstring), new_max * sizeof(algo::cstring));
3460 if (UNLIKELY(!new_mem)) {
3461 FatalErrorExit("command.tary_nomem field:command.acr.field comment:'out of memory'");
3462 }
3463 parent.field_elems = (algo::cstring*)new_mem;
3464 parent.field_max = new_max;
3465 }
3466}
3467
3468// --- command.acr.field.Setary
3469// Copy contents of RHS to PARENT.
3470void command::field_Setary(command::acr& parent, command::acr &rhs) {
3471 field_RemoveAll(parent);
3472 int nnew = rhs.field_n;
3473 field_Reserve(parent, nnew); // reserve space
3474 for (int i = 0; i < nnew; i++) { // copy elements over
3475 new (parent.field_elems + i) algo::cstring(field_qFind(rhs, i));
3476 parent.field_n = i + 1;
3477 }
3478}
3479
3480// --- command.acr.field.Setary2
3481// Copy specified array into field, discarding previous contents.
3482// If the RHS argument aliases the array (refers to the same memory), throw exception.
3483void command::field_Setary(command::acr& parent, const algo::aryptr<algo::cstring> &rhs) {
3484 field_RemoveAll(parent);
3485 field_Addary(parent, rhs);
3486}
3487
3488// --- command.acr.field.AllocNVal
3489// Reserve space. Insert N elements at the end of the array, return pointer to array
3490algo::aryptr<algo::cstring> command::field_AllocNVal(command::acr& parent, int n_elems, const algo::cstring& val) {
3491 field_Reserve(parent, n_elems);
3492 int old_n = parent.field_n;
3493 int new_n = old_n + n_elems;
3494 algo::cstring *elems = parent.field_elems;
3495 for (int i = old_n; i < new_n; i++) {
3496 new (elems + i) algo::cstring(val);
3497 }
3498 parent.field_n = new_n;
3499 return algo::aryptr<algo::cstring>(elems + old_n, n_elems);
3500}
3501
3502// --- command.acr.field.ReadStrptrMaybe
3503// A single element is read from input string and appended to the array.
3504// If the string contains an error, the array is untouched.
3505// Function returns success value.
3506bool command::field_ReadStrptrMaybe(command::acr& parent, algo::strptr in_str) {
3507 bool retval = true;
3508 algo::cstring &elem = field_Alloc(parent);
3509 retval = algo::cstring_ReadStrptrMaybe(elem, in_str);
3510 if (!retval) {
3511 field_RemoveLast(parent);
3512 }
3513 return retval;
3514}
3515
3516// --- command.acr..ReadFieldMaybe
3517bool command::acr_ReadFieldMaybe(command::acr& parent, algo::strptr field, algo::strptr strval) {
3518 bool retval = true;
3519 command::FieldId field_id;
3520 (void)value_SetStrptrMaybe(field_id,algo::Pathcomp(field, ".LL"));
3521 switch(field_id) {
3522 case command_FieldId_query: {
3523 retval = algo::cstring_ReadStrptrMaybe(parent.query, strval);
3524 break;
3525 }
3526 case command_FieldId_where: {
3527 retval = where_ReadStrptrMaybe(parent, strval);
3528 break;
3529 }
3530 case command_FieldId_in: {
3531 retval = algo::cstring_ReadStrptrMaybe(parent.in, strval);
3532 break;
3533 }
3534 case command_FieldId_del: {
3535 retval = bool_ReadStrptrMaybe(parent.del, strval);
3536 break;
3537 }
3538 case command_FieldId_sel: {
3539 retval = bool_ReadStrptrMaybe(parent.sel, strval);
3540 break;
3541 }
3542 case command_FieldId_insert: {
3543 retval = bool_ReadStrptrMaybe(parent.insert, strval);
3544 break;
3545 }
3546 case command_FieldId_replace: {
3547 retval = bool_ReadStrptrMaybe(parent.replace, strval);
3548 break;
3549 }
3550 case command_FieldId_update: {
3551 retval = bool_ReadStrptrMaybe(parent.update, strval);
3552 break;
3553 }
3554 case command_FieldId_merge: {
3555 retval = bool_ReadStrptrMaybe(parent.merge, strval);
3556 break;
3557 }
3558 case command_FieldId_unused: {
3559 retval = bool_ReadStrptrMaybe(parent.unused, strval);
3560 break;
3561 }
3562 case command_FieldId_trunc: {
3563 retval = bool_ReadStrptrMaybe(parent.trunc, strval);
3564 break;
3565 }
3566 case command_FieldId_check: {
3567 retval = bool_ReadStrptrMaybe(parent.check, strval);
3568 break;
3569 }
3570 case command_FieldId_selerr: {
3571 retval = bool_ReadStrptrMaybe(parent.selerr, strval);
3572 break;
3573 }
3574 case command_FieldId_maxshow: {
3575 retval = i32_ReadStrptrMaybe(parent.maxshow, strval);
3576 break;
3577 }
3578 case command_FieldId_write: {
3579 retval = bool_ReadStrptrMaybe(parent.write, strval);
3580 break;
3581 }
3582 case command_FieldId_rename: {
3583 retval = algo::cstring_ReadStrptrMaybe(parent.rename, strval);
3584 break;
3585 }
3586 case command_FieldId_nup: {
3587 retval = i32_ReadStrptrMaybe(parent.nup, strval);
3588 break;
3589 }
3590 case command_FieldId_ndown: {
3591 retval = i32_ReadStrptrMaybe(parent.ndown, strval);
3592 break;
3593 }
3594 case command_FieldId_l: {
3595 retval = bool_ReadStrptrMaybe(parent.l, strval);
3596 break;
3597 }
3598 case command_FieldId_xref: {
3599 retval = bool_ReadStrptrMaybe(parent.xref, strval);
3600 break;
3601 }
3602 case command_FieldId_fldfunc: {
3603 retval = bool_ReadStrptrMaybe(parent.fldfunc, strval);
3604 break;
3605 }
3606 case command_FieldId_maxgroup: {
3607 retval = i32_ReadStrptrMaybe(parent.maxgroup, strval);
3608 break;
3609 }
3610 case command_FieldId_pretty: {
3611 retval = bool_ReadStrptrMaybe(parent.pretty, strval);
3612 break;
3613 }
3614 case command_FieldId_tree: {
3615 retval = bool_ReadStrptrMaybe(parent.tree, strval);
3616 break;
3617 }
3618 case command_FieldId_loose: {
3619 retval = bool_ReadStrptrMaybe(parent.loose, strval);
3620 break;
3621 }
3622 case command_FieldId_my: {
3623 retval = bool_ReadStrptrMaybe(parent.my, strval);
3624 break;
3625 }
3626 case command_FieldId_schema: {
3627 retval = algo::cstring_ReadStrptrMaybe(parent.schema, strval);
3628 break;
3629 }
3630 case command_FieldId_e: {
3631 retval = bool_ReadStrptrMaybe(parent.e, strval);
3632 break;
3633 }
3634 case command_FieldId_t: {
3635 retval = bool_ReadStrptrMaybe(parent.t, strval);
3636 break;
3637 }
3638 case command_FieldId_g: {
3639 retval = bool_ReadStrptrMaybe(parent.g, strval);
3640 break;
3641 }
3642 case command_FieldId_x: {
3643 retval = bool_ReadStrptrMaybe(parent.x, strval);
3644 break;
3645 }
3646 case command_FieldId_rowid: {
3647 retval = bool_ReadStrptrMaybe(parent.rowid, strval);
3648 break;
3649 }
3650 case command_FieldId_cmt: {
3651 retval = bool_ReadStrptrMaybe(parent.cmt, strval);
3652 break;
3653 }
3654 case command_FieldId_report: {
3655 retval = bool_ReadStrptrMaybe(parent.report, strval);
3656 break;
3657 }
3658 case command_FieldId_print: {
3659 retval = bool_ReadStrptrMaybe(parent.print, strval);
3660 break;
3661 }
3662 case command_FieldId_cmd: {
3663 retval = algo::cstring_ReadStrptrMaybe(parent.cmd, strval);
3664 break;
3665 }
3666 case command_FieldId_field: {
3667 retval = field_ReadStrptrMaybe(parent, strval);
3668 break;
3669 }
3670 case command_FieldId_regxof: {
3671 retval = algo::cstring_ReadStrptrMaybe(parent.regxof, strval);
3672 break;
3673 }
3674 case command_FieldId_meta: {
3675 retval = bool_ReadStrptrMaybe(parent.meta, strval);
3676 break;
3677 }
3678 default: break;
3679 }
3680 if (!retval) {
3681 algo_lib::AppendErrtext("attr",field);
3682 }
3683 return retval;
3684}
3685
3686// --- command.acr..ReadTupleMaybe
3687// Read fields of command::acr from attributes of ascii tuple TUPLE
3688bool command::acr_ReadTupleMaybe(command::acr &parent, algo::Tuple &tuple) {
3689 bool retval = true;
3690 int anon_idx = 0;
3691 ind_beg(algo::Tuple_attrs_curs,attr,tuple) {
3692 if (ch_N(attr.name) == 0) {
3693 attr.name = acr_GetAnon(parent, anon_idx++);
3694 }
3695 retval = acr_ReadFieldMaybe(parent, attr.name, attr.value);
3696 if (!retval) {
3697 break;
3698 }
3699 }ind_end;
3700 return retval;
3701}
3702
3703// --- command.acr..Init
3704// Set all fields to initial values.
3705void command::acr_Init(command::acr& parent) {
3706 parent.query = algo::strptr("");
3707 parent.where_elems = 0; // (command.acr.where)
3708 parent.where_n = 0; // (command.acr.where)
3709 parent.where_max = 0; // (command.acr.where)
3710 parent.in = algo::strptr("data");
3711 parent.del = bool(false);
3712 parent.sel = bool(false);
3713 parent.insert = bool(false);
3714 parent.replace = bool(false);
3715 parent.update = bool(false);
3716 parent.merge = bool(false);
3717 parent.unused = bool(false);
3718 parent.trunc = bool(false);
3719 parent.check = bool(false);
3720 parent.selerr = bool(true);
3721 parent.maxshow = i32(100);
3722 parent.write = bool(false);
3723 parent.rename = algo::strptr("");
3724 parent.nup = i32(0);
3725 parent.ndown = i32(0);
3726 parent.l = bool(false);
3727 parent.xref = bool(false);
3728 parent.fldfunc = bool(false);
3729 parent.maxgroup = i32(25);
3730 parent.pretty = bool(true);
3731 parent.tree = bool(false);
3732 parent.loose = bool(false);
3733 parent.my = bool(false);
3734 parent.schema = algo::strptr("data");
3735 parent.e = bool(false);
3736 parent.t = bool(false);
3737 parent.g = bool(false);
3738 parent.x = bool(false);
3739 parent.rowid = bool(false);
3740 parent.cmt = bool(false);
3741 parent.report = bool(true);
3742 parent.print = bool(true);
3743 parent.cmd = algo::strptr("");
3744 parent.field_elems = 0; // (command.acr.field)
3745 parent.field_n = 0; // (command.acr.field)
3746 parent.field_max = 0; // (command.acr.field)
3747 parent.regxof = algo::strptr("");
3748 parent.meta = bool(false);
3749}
3750
3751// --- command.acr..Uninit
3752void command::acr_Uninit(command::acr& parent) {
3753 command::acr &row = parent; (void)row;
3754
3755 // command.acr.field.Uninit (Tary) //Fields to select
3756 // remove all elements from command.acr.field
3757 field_RemoveAll(parent);
3758 // free memory for Tary command.acr.field
3759 algo_lib::malloc_FreeMem(parent.field_elems, sizeof(algo::cstring)*parent.field_max); // (command.acr.field)
3760
3761 // command.acr.where.Uninit (Tary) //Additional key:value pairs to match
3762 // remove all elements from command.acr.where
3763 where_RemoveAll(parent);
3764 // free memory for Tary command.acr.where
3765 algo_lib::malloc_FreeMem(parent.where_elems, sizeof(algo::cstring)*parent.where_max); // (command.acr.where)
3766}
3767
3768// --- command.acr..ToCmdline
3769// Convenience function that returns a full command line
3770// Assume command is in a directory called bin
3771tempstr command::acr_ToCmdline(command::acr& row) {
3772 tempstr ret;
3773 ret << "bin/acr ";
3774 acr_PrintArgv(row, ret);
3775 // inherit less intense verbose, debug options
3776 for (int i = 1; i < algo_lib::_db.cmdline.verbose; i++) {
3777 ret << " -verbose";
3778 }
3779 for (int i = 1; i < algo_lib::_db.cmdline.debug; i++) {
3780 ret << " -debug";
3781 }
3782 return ret;
3783}
3784
3785// --- command.acr..PrintArgv
3786// print string representation of ROW to string STR
3787// cfmt:command.acr.Argv printfmt:Auto
3788void command::acr_PrintArgv(command::acr& row, algo::cstring& str) {
3789 algo::tempstr temp;
3790 (void)temp;
3791 (void)str;
3792 ch_RemoveAll(temp);
3793 cstring_Print(row.query, temp);
3794 str << " -query:";
3795 strptr_PrintBash(temp,str);
3796 ind_beg(acr_where_curs,value,row) {
3797 ch_RemoveAll(temp);
3798 cstring_Print(value, temp);
3799 str << " -where:";
3800 strptr_PrintBash(temp,str);
3801 }ind_end;
3802 if (!(row.in == "data")) {
3803 ch_RemoveAll(temp);
3804 cstring_Print(row.in, temp);
3805 str << " -in:";
3806 strptr_PrintBash(temp,str);
3807 }
3808 if (!(row.del == false)) {
3809 ch_RemoveAll(temp);
3810 bool_Print(row.del, temp);
3811 str << " -del:";
3812 strptr_PrintBash(temp,str);
3813 }
3814 if (!(row.sel == false)) {
3815 ch_RemoveAll(temp);
3816 bool_Print(row.sel, temp);
3817 str << " -sel:";
3818 strptr_PrintBash(temp,str);
3819 }
3820 if (!(row.insert == false)) {
3821 ch_RemoveAll(temp);
3822 bool_Print(row.insert, temp);
3823 str << " -insert:";
3824 strptr_PrintBash(temp,str);
3825 }
3826 if (!(row.replace == false)) {
3827 ch_RemoveAll(temp);
3828 bool_Print(row.replace, temp);
3829 str << " -replace:";
3830 strptr_PrintBash(temp,str);
3831 }
3832 if (!(row.update == false)) {
3833 ch_RemoveAll(temp);
3834 bool_Print(row.update, temp);
3835 str << " -update:";
3836 strptr_PrintBash(temp,str);
3837 }
3838 if (!(row.merge == false)) {
3839 ch_RemoveAll(temp);
3840 bool_Print(row.merge, temp);
3841 str << " -merge:";
3842 strptr_PrintBash(temp,str);
3843 }
3844 if (!(row.unused == false)) {
3845 ch_RemoveAll(temp);
3846 bool_Print(row.unused, temp);
3847 str << " -unused:";
3848 strptr_PrintBash(temp,str);
3849 }
3850 if (!(row.trunc == false)) {
3851 ch_RemoveAll(temp);
3852 bool_Print(row.trunc, temp);
3853 str << " -trunc:";
3854 strptr_PrintBash(temp,str);
3855 }
3856 if (!(row.check == false)) {
3857 ch_RemoveAll(temp);
3858 bool_Print(row.check, temp);
3859 str << " -check:";
3860 strptr_PrintBash(temp,str);
3861 }
3862 if (!(row.selerr == true)) {
3863 ch_RemoveAll(temp);
3864 bool_Print(row.selerr, temp);
3865 str << " -selerr:";
3866 strptr_PrintBash(temp,str);
3867 }
3868 if (!(row.maxshow == 100)) {
3869 ch_RemoveAll(temp);
3870 i32_Print(row.maxshow, temp);
3871 str << " -maxshow:";
3872 strptr_PrintBash(temp,str);
3873 }
3874 if (!(row.write == false)) {
3875 ch_RemoveAll(temp);
3876 bool_Print(row.write, temp);
3877 str << " -write:";
3878 strptr_PrintBash(temp,str);
3879 }
3880 if (!(row.rename == "")) {
3881 ch_RemoveAll(temp);
3882 cstring_Print(row.rename, temp);
3883 str << " -rename:";
3884 strptr_PrintBash(temp,str);
3885 }
3886 if (!(row.nup == 0)) {
3887 ch_RemoveAll(temp);
3888 i32_Print(row.nup, temp);
3889 str << " -nup:";
3890 strptr_PrintBash(temp,str);
3891 }
3892 if (!(row.ndown == 0)) {
3893 ch_RemoveAll(temp);
3894 i32_Print(row.ndown, temp);
3895 str << " -ndown:";
3896 strptr_PrintBash(temp,str);
3897 }
3898 if (!(row.l == false)) {
3899 ch_RemoveAll(temp);
3900 bool_Print(row.l, temp);
3901 str << " -l:";
3902 strptr_PrintBash(temp,str);
3903 }
3904 if (!(row.xref == false)) {
3905 ch_RemoveAll(temp);
3906 bool_Print(row.xref, temp);
3907 str << " -xref:";
3908 strptr_PrintBash(temp,str);
3909 }
3910 if (!(row.fldfunc == false)) {
3911 ch_RemoveAll(temp);
3912 bool_Print(row.fldfunc, temp);
3913 str << " -fldfunc:";
3914 strptr_PrintBash(temp,str);
3915 }
3916 if (!(row.maxgroup == 25)) {
3917 ch_RemoveAll(temp);
3918 i32_Print(row.maxgroup, temp);
3919 str << " -maxgroup:";
3920 strptr_PrintBash(temp,str);
3921 }
3922 if (!(row.pretty == true)) {
3923 ch_RemoveAll(temp);
3924 bool_Print(row.pretty, temp);
3925 str << " -pretty:";
3926 strptr_PrintBash(temp,str);
3927 }
3928 if (!(row.tree == false)) {
3929 ch_RemoveAll(temp);
3930 bool_Print(row.tree, temp);
3931 str << " -tree:";
3932 strptr_PrintBash(temp,str);
3933 }
3934 if (!(row.loose == false)) {
3935 ch_RemoveAll(temp);
3936 bool_Print(row.loose, temp);
3937 str << " -loose:";
3938 strptr_PrintBash(temp,str);
3939 }
3940 if (!(row.my == false)) {
3941 ch_RemoveAll(temp);
3942 bool_Print(row.my, temp);
3943 str << " -my:";
3944 strptr_PrintBash(temp,str);
3945 }
3946 if (!(row.schema == "data")) {
3947 ch_RemoveAll(temp);
3948 cstring_Print(row.schema, temp);
3949 str << " -schema:";
3950 strptr_PrintBash(temp,str);
3951 }
3952 if (!(row.e == false)) {
3953 ch_RemoveAll(temp);
3954 bool_Print(row.e, temp);
3955 str << " -e:";
3956 strptr_PrintBash(temp,str);
3957 }
3958 if (!(row.t == false)) {
3959 ch_RemoveAll(temp);
3960 bool_Print(row.t, temp);
3961 str << " -t:";
3962 strptr_PrintBash(temp,str);
3963 }
3964 if (!(row.g == false)) {
3965 ch_RemoveAll(temp);
3966 bool_Print(row.g, temp);
3967 str << " -g:";
3968 strptr_PrintBash(temp,str);
3969 }
3970 if (!(row.x == false)) {
3971 ch_RemoveAll(temp);
3972 bool_Print(row.x, temp);
3973 str << " -x:";
3974 strptr_PrintBash(temp,str);
3975 }
3976 if (!(row.rowid == false)) {
3977 ch_RemoveAll(temp);
3978 bool_Print(row.rowid, temp);
3979 str << " -rowid:";
3980 strptr_PrintBash(temp,str);
3981 }
3982 if (!(row.cmt == false)) {
3983 ch_RemoveAll(temp);
3984 bool_Print(row.cmt, temp);
3985 str << " -cmt:";
3986 strptr_PrintBash(temp,str);
3987 }
3988 if (!(row.report == true)) {
3989 ch_RemoveAll(temp);
3990 bool_Print(row.report, temp);
3991 str << " -report:";
3992 strptr_PrintBash(temp,str);
3993 }
3994 if (!(row.print == true)) {
3995 ch_RemoveAll(temp);
3996 bool_Print(row.print, temp);
3997 str << " -print:";
3998 strptr_PrintBash(temp,str);
3999 }
4000 if (!(row.cmd == "")) {
4001 ch_RemoveAll(temp);
4002 cstring_Print(row.cmd, temp);
4003 str << " -cmd:";
4004 strptr_PrintBash(temp,str);
4005 }
4006 ind_beg(acr_field_curs,value,row) {
4007 ch_RemoveAll(temp);
4008 cstring_Print(value, temp);
4009 str << " -field:";
4010 strptr_PrintBash(temp,str);
4011 }ind_end;
4012 if (!(row.regxof == "")) {
4013 ch_RemoveAll(temp);
4014 cstring_Print(row.regxof, temp);
4015 str << " -regxof:";
4016 strptr_PrintBash(temp,str);
4017 }
4018 if (!(row.meta == false)) {
4019 ch_RemoveAll(temp);
4020 bool_Print(row.meta, temp);
4021 str << " -meta:";
4022 strptr_PrintBash(temp,str);
4023 }
4024}
4025
4026// --- command.acr..GetAnon
4027algo::strptr command::acr_GetAnon(command::acr &parent, i32 idx) {
4028 (void)parent;//only to avoid -Wunused-parameter
4029 switch(idx) {
4030 case(0): return strptr("query", 5);
4031 default: return algo::strptr();
4032 }
4033}
4034
4035// --- command.acr..NArgs
4036// Used with command lines
4037// Return # of command-line arguments that must follow this argument
4038// If FIELD is invalid, return -1
4039i32 command::acr_NArgs(command::FieldId field, algo::strptr& out_dflt, bool* out_anon) {
4040 i32 retval = 1;
4041 switch (field) {
4042 case command_FieldId_query: { // $comment
4043 *out_anon = true;
4044 } break;
4045 case command_FieldId_where: { // $comment
4046 *out_anon = false;
4047 } break;
4048 case command_FieldId_in: { // $comment
4049 *out_anon = false;
4050 } break;
4051 case command_FieldId_del: { // $comment
4052 *out_anon = false;
4053 retval=0;
4054 out_dflt="Y";
4055 } break;
4056 case command_FieldId_sel: { // bool: no argument required but value may be specified as del:Y
4057 *out_anon = false;
4058 retval=0;
4059 out_dflt="Y";
4060 } break;
4061 case command_FieldId_insert: { // bool: no argument required but value may be specified as sel:Y
4062 *out_anon = false;
4063 retval=0;
4064 out_dflt="Y";
4065 } break;
4066 case command_FieldId_replace: { // bool: no argument required but value may be specified as insert:Y
4067 *out_anon = false;
4068 retval=0;
4069 out_dflt="Y";
4070 } break;
4071 case command_FieldId_update: { // bool: no argument required but value may be specified as replace:Y
4072 *out_anon = false;
4073 retval=0;
4074 out_dflt="Y";
4075 } break;
4076 case command_FieldId_merge: { // bool: no argument required but value may be specified as update:Y
4077 *out_anon = false;
4078 retval=0;
4079 out_dflt="Y";
4080 } break;
4081 case command_FieldId_unused: { // bool: no argument required but value may be specified as merge:Y
4082 *out_anon = false;
4083 retval=0;
4084 out_dflt="Y";
4085 } break;
4086 case command_FieldId_trunc: { // bool: no argument required but value may be specified as unused:Y
4087 *out_anon = false;
4088 retval=0;
4089 out_dflt="Y";
4090 } break;
4091 case command_FieldId_check: { // bool: no argument required but value may be specified as trunc:Y
4092 *out_anon = false;
4093 retval=0;
4094 out_dflt="Y";
4095 } break;
4096 case command_FieldId_selerr: { // bool: no argument required but value may be specified as check:Y
4097 *out_anon = false;
4098 retval=0;
4099 out_dflt="Y";
4100 } break;
4101 case command_FieldId_maxshow: { // bool: no argument required but value may be specified as selerr:Y
4102 *out_anon = false;
4103 } break;
4104 case command_FieldId_write: { // bool: no argument required but value may be specified as selerr:Y
4105 *out_anon = false;
4106 retval=0;
4107 out_dflt="Y";
4108 } break;
4109 case command_FieldId_rename: { // bool: no argument required but value may be specified as write:Y
4110 *out_anon = false;
4111 } break;
4112 case command_FieldId_nup: { // bool: no argument required but value may be specified as write:Y
4113 *out_anon = false;
4114 } break;
4115 case command_FieldId_ndown: { // bool: no argument required but value may be specified as write:Y
4116 *out_anon = false;
4117 } break;
4118 case command_FieldId_l: { // bool: no argument required but value may be specified as write:Y
4119 *out_anon = false;
4120 retval=0;
4121 out_dflt="Y";
4122 } break;
4123 case command_FieldId_xref: { // bool: no argument required but value may be specified as l:Y
4124 *out_anon = false;
4125 retval=0;
4126 out_dflt="Y";
4127 } break;
4128 case command_FieldId_fldfunc: { // bool: no argument required but value may be specified as xref:Y
4129 *out_anon = false;
4130 retval=0;
4131 out_dflt="Y";
4132 } break;
4133 case command_FieldId_maxgroup: { // bool: no argument required but value may be specified as fldfunc:Y
4134 *out_anon = false;
4135 } break;
4136 case command_FieldId_pretty: { // bool: no argument required but value may be specified as fldfunc:Y
4137 *out_anon = false;
4138 retval=0;
4139 out_dflt="Y";
4140 } break;
4141 case command_FieldId_tree: { // bool: no argument required but value may be specified as pretty:Y
4142 *out_anon = false;
4143 retval=0;
4144 out_dflt="Y";
4145 } break;
4146 case command_FieldId_loose: { // bool: no argument required but value may be specified as tree:Y
4147 *out_anon = false;
4148 retval=0;
4149 out_dflt="Y";
4150 } break;
4151 case command_FieldId_my: { // bool: no argument required but value may be specified as loose:Y
4152 *out_anon = false;
4153 retval=0;
4154 out_dflt="Y";
4155 } break;
4156 case command_FieldId_schema: { // bool: no argument required but value may be specified as my:Y
4157 *out_anon = false;
4158 } break;
4159 case command_FieldId_e: { // bool: no argument required but value may be specified as my:Y
4160 *out_anon = false;
4161 retval=0;
4162 out_dflt="Y";
4163 } break;
4164 case command_FieldId_t: { // bool: no argument required but value may be specified as e:Y
4165 *out_anon = false;
4166 retval=0;
4167 out_dflt="Y";
4168 } break;
4169 case command_FieldId_g: { // bool: no argument required but value may be specified as t:Y
4170 *out_anon = false;
4171 retval=0;
4172 out_dflt="Y";
4173 } break;
4174 case command_FieldId_x: { // bool: no argument required but value may be specified as g:Y
4175 *out_anon = false;
4176 retval=0;
4177 out_dflt="Y";
4178 } break;
4179 case command_FieldId_rowid: { // bool: no argument required but value may be specified as x:Y
4180 *out_anon = false;
4181 retval=0;
4182 out_dflt="Y";
4183 } break;
4184 case command_FieldId_cmt: { // bool: no argument required but value may be specified as rowid:Y
4185 *out_anon = false;
4186 retval=0;
4187 out_dflt="Y";
4188 } break;
4189 case command_FieldId_report: { // bool: no argument required but value may be specified as cmt:Y
4190 *out_anon = false;
4191 retval=0;
4192 out_dflt="Y";
4193 } break;
4194 case command_FieldId_print: { // bool: no argument required but value may be specified as report:Y
4195 *out_anon = false;
4196 retval=0;
4197 out_dflt="Y";
4198 } break;
4199 case command_FieldId_cmd: { // bool: no argument required but value may be specified as print:Y
4200 *out_anon = false;
4201 } break;
4202 case command_FieldId_field: { // bool: no argument required but value may be specified as print:Y
4203 *out_anon = false;
4204 } break;
4205 case command_FieldId_regxof: { // bool: no argument required but value may be specified as print:Y
4206 *out_anon = false;
4207 } break;
4208 case command_FieldId_meta: { // bool: no argument required but value may be specified as print:Y
4209 *out_anon = false;
4210 retval=0;
4211 out_dflt="Y";
4212 } break;
4213 default:
4214 retval=-1; // unrecognized
4215 }
4216 return retval;
4217}
4218
4219// --- command.acr_compl..ReadFieldMaybe
4220bool command::acr_compl_ReadFieldMaybe(command::acr_compl& parent, algo::strptr field, algo::strptr strval) {
4221 bool retval = true;
4222 command::FieldId field_id;
4223 (void)value_SetStrptrMaybe(field_id,field);
4224 switch(field_id) {
4225 case command_FieldId_data: {
4226 retval = algo::cstring_ReadStrptrMaybe(parent.data, strval);
4227 break;
4228 }
4229 case command_FieldId_schema: {
4230 retval = algo::cstring_ReadStrptrMaybe(parent.schema, strval);
4231 break;
4232 }
4233 case command_FieldId_line: {
4234 retval = algo::cstring_ReadStrptrMaybe(parent.line, strval);
4235 break;
4236 }
4237 case command_FieldId_point: {
4238 retval = algo::cstring_ReadStrptrMaybe(parent.point, strval);
4239 break;
4240 }
4241 case command_FieldId_type: {
4242 retval = algo::cstring_ReadStrptrMaybe(parent.type, strval);
4243 break;
4244 }
4245 case command_FieldId_install: {
4246 retval = bool_ReadStrptrMaybe(parent.install, strval);
4247 break;
4248 }
4249 case command_FieldId_debug_log: {
4250 retval = algo::cstring_ReadStrptrMaybe(parent.debug_log, strval);
4251 break;
4252 }
4253 default: break;
4254 }
4255 if (!retval) {
4256 algo_lib::AppendErrtext("attr",field);
4257 }
4258 return retval;
4259}
4260
4261// --- command.acr_compl..ReadStrptrMaybe
4262// Read fields of command::acr_compl from an ascii string.
4263// The format of the string is an ssim Tuple
4264bool command::acr_compl_ReadStrptrMaybe(command::acr_compl &parent, algo::strptr in_str) {
4265 bool retval = true;
4266 retval = algo::StripTypeTag(in_str, "command.acr_compl");
4267 ind_beg(algo::Attr_curs, attr, in_str) {
4268 retval = retval && acr_compl_ReadFieldMaybe(parent, attr.name, attr.value);
4269 }ind_end;
4270 return retval;
4271}
4272
4273// --- command.acr_compl..ReadTupleMaybe
4274// Read fields of command::acr_compl from attributes of ascii tuple TUPLE
4275bool command::acr_compl_ReadTupleMaybe(command::acr_compl &parent, algo::Tuple &tuple) {
4276 bool retval = true;
4277 ind_beg(algo::Tuple_attrs_curs,attr,tuple) {
4278 retval = acr_compl_ReadFieldMaybe(parent, attr.name, attr.value);
4279 if (!retval) {
4280 break;
4281 }
4282 }ind_end;
4283 return retval;
4284}
4285
4286// --- command.acr_compl..ToCmdline
4287// Convenience function that returns a full command line
4288// Assume command is in a directory called bin
4289tempstr command::acr_compl_ToCmdline(command::acr_compl& row) {
4290 tempstr ret;
4291 ret << "bin/acr_compl ";
4292 acr_compl_PrintArgv(row, ret);
4293 // inherit less intense verbose, debug options
4294 for (int i = 1; i < algo_lib::_db.cmdline.verbose; i++) {
4295 ret << " -verbose";
4296 }
4297 for (int i = 1; i < algo_lib::_db.cmdline.debug; i++) {
4298 ret << " -debug";
4299 }
4300 return ret;
4301}
4302
4303// --- command.acr_compl..PrintArgv
4304// print string representation of ROW to string STR
4305// cfmt:command.acr_compl.Argv printfmt:Auto
4306void command::acr_compl_PrintArgv(command::acr_compl& row, algo::cstring& str) {
4307 algo::tempstr temp;
4308 (void)temp;
4309 (void)str;
4310 if (!(row.data == "data")) {
4311 ch_RemoveAll(temp);
4312 cstring_Print(row.data, temp);
4313 str << " -data:";
4314 strptr_PrintBash(temp,str);
4315 }
4316 if (!(row.schema == "data")) {
4317 ch_RemoveAll(temp);
4318 cstring_Print(row.schema, temp);
4319 str << " -schema:";
4320 strptr_PrintBash(temp,str);
4321 }
4322 if (!(row.line == "")) {
4323 ch_RemoveAll(temp);
4324 cstring_Print(row.line, temp);
4325 str << " -line:";
4326 strptr_PrintBash(temp,str);
4327 }
4328 if (!(row.point == "")) {
4329 ch_RemoveAll(temp);
4330 cstring_Print(row.point, temp);
4331 str << " -point:";
4332 strptr_PrintBash(temp,str);
4333 }
4334 if (!(row.type == "9")) {
4335 ch_RemoveAll(temp);
4336 cstring_Print(row.type, temp);
4337 str << " -type:";
4338 strptr_PrintBash(temp,str);
4339 }
4340 if (!(row.install == false)) {
4341 ch_RemoveAll(temp);
4342 bool_Print(row.install, temp);
4343 str << " -install:";
4344 strptr_PrintBash(temp,str);
4345 }
4346 if (!(row.debug_log == "")) {
4347 ch_RemoveAll(temp);
4348 cstring_Print(row.debug_log, temp);
4349 str << " -debug_log:";
4350 strptr_PrintBash(temp,str);
4351 }
4352}
4353
4354// --- command.acr_compl..Print
4355// print string representation of ROW to string STR
4356// cfmt:command.acr_compl.String printfmt:Tuple
4357void command::acr_compl_Print(command::acr_compl& row, algo::cstring& str) {
4358 algo::tempstr temp;
4359 str << "command.acr_compl";
4360
4361 algo::cstring_Print(row.data, temp);
4362 PrintAttrSpaceReset(str,"data", temp);
4363
4364 algo::cstring_Print(row.schema, temp);
4365 PrintAttrSpaceReset(str,"schema", temp);
4366
4367 algo::cstring_Print(row.line, temp);
4368 PrintAttrSpaceReset(str,"line", temp);
4369
4370 algo::cstring_Print(row.point, temp);
4371 PrintAttrSpaceReset(str,"point", temp);
4372
4373 algo::cstring_Print(row.type, temp);
4374 PrintAttrSpaceReset(str,"type", temp);
4375
4376 bool_Print(row.install, temp);
4377 PrintAttrSpaceReset(str,"install", temp);
4378
4379 algo::cstring_Print(row.debug_log, temp);
4380 PrintAttrSpaceReset(str,"debug_log", temp);
4381}
4382
4383// --- command.acr_compl..NArgs
4384// Used with command lines
4385// Return # of command-line arguments that must follow this argument
4386// If FIELD is invalid, return -1
4387i32 command::acr_compl_NArgs(command::FieldId field, algo::strptr& out_dflt, bool* out_anon) {
4388 i32 retval = 1;
4389 switch (field) {
4390 case command_FieldId_data: { // $comment
4391 *out_anon = false;
4392 } break;
4393 case command_FieldId_schema: { // $comment
4394 *out_anon = false;
4395 } break;
4396 case command_FieldId_line: { // $comment
4397 *out_anon = false;
4398 } break;
4399 case command_FieldId_point: { // $comment
4400 *out_anon = false;
4401 } break;
4402 case command_FieldId_type: { // $comment
4403 *out_anon = false;
4404 } break;
4405 case command_FieldId_install: { // $comment
4406 *out_anon = false;
4407 retval=0;
4408 out_dflt="Y";
4409 } break;
4410 case command_FieldId_debug_log: { // bool: no argument required but value may be specified as install:Y
4411 *out_anon = false;
4412 } break;
4413 default:
4414 retval=-1; // unrecognized
4415 }
4416 return retval;
4417}
4418
4419// --- command.acr_compl_proc.acr_compl.Start
4420// Start subprocess
4421// If subprocess already running, do nothing. Otherwise, start it
4422int command::acr_compl_Start(command::acr_compl_proc& parent) {
4423 int retval = 0;
4424 if (parent.pid == 0) {
4425 verblog(acr_compl_ToCmdline(parent)); // maybe print command
4426#ifdef WIN32
4427 algo_lib::ResolveExecFname(parent.path);
4428 tempstr cmdline(acr_compl_ToCmdline(parent));
4429 parent.pid = dospawn(Zeroterm(parent.path),Zeroterm(cmdline),parent.timeout,parent.fstdin,parent.fstdout,parent.fstderr);
4430#else
4431 parent.pid = fork();
4432 if (parent.pid == 0) { // child
4433 algo_lib::DieWithParent();
4434 if (parent.timeout > 0) {
4435 alarm(parent.timeout);
4436 }
4437 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstdin , 0);
4438 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstdout, 1);
4439 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstderr, 2);
4440 if (retval==0) retval= acr_compl_Execv(parent);
4441 if (retval != 0) { // if start fails, print error
4442 int err=errno;
4443 prerr("command.acr_compl_execv"
4444 <<Keyval("errno",err)
4445 <<Keyval("errstr",strerror(err))
4446 <<Keyval("comment","Execv failed"));
4447 }
4448 _exit(127); // if failed to start, exit anyway
4449 } else if (parent.pid == -1) {
4450 retval = errno; // failed to fork
4451 }
4452#endif
4453 }
4454 parent.status = parent.pid > 0 ? 0 : -1; // if didn't start, set error status
4455 return retval;
4456}
4457
4458// --- command.acr_compl_proc.acr_compl.StartRead
4459// Start subprocess & Read output
4460algo::Fildes command::acr_compl_StartRead(command::acr_compl_proc& parent, algo_lib::FFildes &read) {
4461 int pipefd[2];
4462 int rc=pipe(pipefd);
4463 (void)rc;
4464 read.fd.value = pipefd[0];
4465 parent.fstdout << ">&" << pipefd[1];
4466 acr_compl_Start(parent);
4467 (void)close(pipefd[1]);
4468 return read.fd;
4469}
4470
4471// --- command.acr_compl_proc.acr_compl.Kill
4472// Kill subprocess and wait
4473void command::acr_compl_Kill(command::acr_compl_proc& parent) {
4474 if (parent.pid != 0) {
4475 kill(parent.pid,9);
4476 acr_compl_Wait(parent);
4477 }
4478}
4479
4480// --- command.acr_compl_proc.acr_compl.Wait
4481// Wait for subprocess to return
4482void command::acr_compl_Wait(command::acr_compl_proc& parent) {
4483 if (parent.pid > 0) {
4484 int wait_flags = 0;
4485 int wait_status = 0;
4486 int rc = -1;
4487 do {
4488 // really wait for subprocess to exit
4489 rc = waitpid(parent.pid,&wait_status,wait_flags);
4490 } while (rc==-1 && errno==EINTR);
4491 if (rc == parent.pid) {
4492 parent.status = wait_status;
4493 parent.pid = 0;
4494 }
4495 }
4496}
4497
4498// --- command.acr_compl_proc.acr_compl.Exec
4499// Start + Wait
4500// Execute subprocess and return exit code
4501int command::acr_compl_Exec(command::acr_compl_proc& parent) {
4502 acr_compl_Start(parent);
4503 acr_compl_Wait(parent);
4504 return parent.status;
4505}
4506
4507// --- command.acr_compl_proc.acr_compl.ExecX
4508// Start + Wait, throw exception on error
4509// Execute subprocess; throw human-readable exception on error
4510void command::acr_compl_ExecX(command::acr_compl_proc& parent) {
4511 int rc = acr_compl_Exec(parent);
4512 vrfy(rc==0, tempstr() << "algo_lib.exec" << Keyval("cmd",acr_compl_ToCmdline(parent))
4513 << Keyval("comment",algo::DescribeWaitStatus(parent.status)));
4514}
4515
4516// --- command.acr_compl_proc.acr_compl.Execv
4517// Call execv()
4518// Call execv with specified parameters
4519int command::acr_compl_Execv(command::acr_compl_proc& parent) {
4520 int ret = 0;
4521 algo::StringAry args;
4522 acr_compl_ToArgv(parent, args);
4523 char **argv = (char**)alloca((ary_N(args)+1)*sizeof(*argv));
4524 ind_beg(algo::StringAry_ary_curs,arg,args) {
4525 argv[ind_curs(arg).index] = Zeroterm(arg);
4526 }ind_end;
4527 argv[ary_N(args)] = NULL;
4528 // if parent.path is relative, search for it in PATH
4529 algo_lib::ResolveExecFname(parent.path);
4530 ret = execv(Zeroterm(parent.path),argv);
4531 return ret;
4532}
4533
4534// --- command.acr_compl_proc.acr_compl.ToCmdline
4535algo::tempstr command::acr_compl_ToCmdline(command::acr_compl_proc& parent) {
4536 algo::tempstr retval;
4537 retval << parent.path << " ";
4538 command::acr_compl_PrintArgv(parent.cmd,retval);
4539 if (ch_N(parent.fstdin)) {
4540 retval << " " << parent.fstdin;
4541 }
4542 if (ch_N(parent.fstdout)) {
4543 retval << " " << parent.fstdout;
4544 }
4545 if (ch_N(parent.fstderr)) {
4546 retval << " 2" << parent.fstderr;
4547 }
4548 return retval;
4549}
4550
4551// --- command.acr_compl_proc.acr_compl.ToArgv
4552// Form array from the command line
4553void command::acr_compl_ToArgv(command::acr_compl_proc& parent, algo::StringAry& args) {
4554 ary_RemoveAll(args);
4555 ary_Alloc(args) << parent.path;
4556
4557 if (parent.cmd.data != "data") {
4558 cstring *arg = &ary_Alloc(args);
4559 *arg << "-data:";
4560 cstring_Print(parent.cmd.data, *arg);
4561 }
4562
4563 if (parent.cmd.schema != "data") {
4564 cstring *arg = &ary_Alloc(args);
4565 *arg << "-schema:";
4566 cstring_Print(parent.cmd.schema, *arg);
4567 }
4568
4569 if (parent.cmd.line != "") {
4570 cstring *arg = &ary_Alloc(args);
4571 *arg << "-line:";
4572 cstring_Print(parent.cmd.line, *arg);
4573 }
4574
4575 if (parent.cmd.point != "") {
4576 cstring *arg = &ary_Alloc(args);
4577 *arg << "-point:";
4578 cstring_Print(parent.cmd.point, *arg);
4579 }
4580
4581 if (parent.cmd.type != "9") {
4582 cstring *arg = &ary_Alloc(args);
4583 *arg << "-type:";
4584 cstring_Print(parent.cmd.type, *arg);
4585 }
4586
4587 if (parent.cmd.install != false) {
4588 cstring *arg = &ary_Alloc(args);
4589 *arg << "-install:";
4590 bool_Print(parent.cmd.install, *arg);
4591 }
4592
4593 if (parent.cmd.debug_log != "") {
4594 cstring *arg = &ary_Alloc(args);
4595 *arg << "-debug_log:";
4596 cstring_Print(parent.cmd.debug_log, *arg);
4597 }
4598 for (int i=1; i < algo_lib::_db.cmdline.verbose; ++i) {
4599 ary_Alloc(args) << "-verbose";
4600 }
4601}
4602
4603// --- command.acr_compl_proc..Uninit
4604void command::acr_compl_proc_Uninit(command::acr_compl_proc& parent) {
4605 command::acr_compl_proc &row = parent; (void)row;
4606
4607 // command.acr_compl_proc.acr_compl.Uninit (Exec) //
4608 acr_compl_Kill(parent); // kill child, ensure forward progress
4609}
4610
4611// --- command.acr_dm.arg.Addary
4612// Reserve space (this may move memory). Insert N element at the end.
4613// Return aryptr to newly inserted block.
4614// If the RHS argument aliases the array (refers to the same memory), exit program with fatal error.
4615algo::aryptr<algo::cstring> command::arg_Addary(command::acr_dm& parent, algo::aryptr<algo::cstring> rhs) {
4616 bool overlaps = rhs.n_elems>0 && rhs.elems >= parent.arg_elems && rhs.elems < parent.arg_elems + parent.arg_max;
4617 if (UNLIKELY(overlaps)) {
4618 FatalErrorExit("command.tary_alias field:command.acr_dm.arg comment:'alias error: sub-array is being appended to the whole'");
4619 }
4620 int nnew = rhs.n_elems;
4621 arg_Reserve(parent, nnew); // reserve space
4622 int at = parent.arg_n;
4623 for (int i = 0; i < nnew; i++) {
4624 new (parent.arg_elems + at + i) algo::cstring(rhs[i]);
4625 parent.arg_n++;
4626 }
4627 return algo::aryptr<algo::cstring>(parent.arg_elems + at, nnew);
4628}
4629
4630// --- command.acr_dm.arg.Alloc
4631// Reserve space. Insert element at the end
4632// The new element is initialized to a default value
4633algo::cstring& command::arg_Alloc(command::acr_dm& parent) {
4634 arg_Reserve(parent, 1);
4635 int n = parent.arg_n;
4636 int at = n;
4637 algo::cstring *elems = parent.arg_elems;
4638 new (elems + at) algo::cstring(); // construct new element, default initializer
4639 parent.arg_n = n+1;
4640 return elems[at];
4641}
4642
4643// --- command.acr_dm.arg.AllocAt
4644// Reserve space for new element, reallocating the array if necessary
4645// Insert new element at specified index. Index must be in range or a fatal error occurs.
4646algo::cstring& command::arg_AllocAt(command::acr_dm& parent, int at) {
4647 arg_Reserve(parent, 1);
4648 int n = parent.arg_n;
4649 if (UNLIKELY(u64(at) >= u64(n+1))) {
4650 FatalErrorExit("command.bad_alloc_at field:command.acr_dm.arg comment:'index out of range'");
4651 }
4652 algo::cstring *elems = parent.arg_elems;
4653 memmove(elems + at + 1, elems + at, (n - at) * sizeof(algo::cstring));
4654 new (elems + at) algo::cstring(); // construct element, default initializer
4655 parent.arg_n = n+1;
4656 return elems[at];
4657}
4658
4659// --- command.acr_dm.arg.AllocN
4660// Reserve space. Insert N elements at the end of the array, return pointer to array
4661algo::aryptr<algo::cstring> command::arg_AllocN(command::acr_dm& parent, int n_elems) {
4662 arg_Reserve(parent, n_elems);
4663 int old_n = parent.arg_n;
4664 int new_n = old_n + n_elems;
4665 algo::cstring *elems = parent.arg_elems;
4666 for (int i = old_n; i < new_n; i++) {
4667 new (elems + i) algo::cstring(); // construct new element, default initialize
4668 }
4669 parent.arg_n = new_n;
4670 return algo::aryptr<algo::cstring>(elems + old_n, n_elems);
4671}
4672
4673// --- command.acr_dm.arg.Remove
4674// Remove item by index. If index outside of range, do nothing.
4675void command::arg_Remove(command::acr_dm& parent, u32 i) {
4676 u32 lim = parent.arg_n;
4677 algo::cstring *elems = parent.arg_elems;
4678 if (i < lim) {
4679 elems[i].~cstring(); // destroy element
4680 memmove(elems + i, elems + (i + 1), sizeof(algo::cstring) * (lim - (i + 1)));
4681 parent.arg_n = lim - 1;
4682 }
4683}
4684
4685// --- command.acr_dm.arg.RemoveAll
4686void command::arg_RemoveAll(command::acr_dm& parent) {
4687 u32 n = parent.arg_n;
4688 while (n > 0) {
4689 n -= 1;
4690 parent.arg_elems[n].~cstring();
4691 parent.arg_n = n;
4692 }
4693}
4694
4695// --- command.acr_dm.arg.RemoveLast
4696// Delete last element of array. Do nothing if array is empty.
4697void command::arg_RemoveLast(command::acr_dm& parent) {
4698 u64 n = parent.arg_n;
4699 if (n > 0) {
4700 n -= 1;
4701 arg_qFind(parent, u64(n)).~cstring();
4702 parent.arg_n = n;
4703 }
4704}
4705
4706// --- command.acr_dm.arg.AbsReserve
4707// Make sure N elements fit in array. Process dies if out of memory
4708void command::arg_AbsReserve(command::acr_dm& parent, int n) {
4709 u32 old_max = parent.arg_max;
4710 if (n > i32(old_max)) {
4711 u32 new_max = i32_Max(i32_Max(old_max * 2, n), 4);
4712 void *new_mem = algo_lib::malloc_ReallocMem(parent.arg_elems, old_max * sizeof(algo::cstring), new_max * sizeof(algo::cstring));
4713 if (UNLIKELY(!new_mem)) {
4714 FatalErrorExit("command.tary_nomem field:command.acr_dm.arg comment:'out of memory'");
4715 }
4716 parent.arg_elems = (algo::cstring*)new_mem;
4717 parent.arg_max = new_max;
4718 }
4719}
4720
4721// --- command.acr_dm.arg.Setary
4722// Copy contents of RHS to PARENT.
4723void command::arg_Setary(command::acr_dm& parent, command::acr_dm &rhs) {
4724 arg_RemoveAll(parent);
4725 int nnew = rhs.arg_n;
4726 arg_Reserve(parent, nnew); // reserve space
4727 for (int i = 0; i < nnew; i++) { // copy elements over
4728 new (parent.arg_elems + i) algo::cstring(arg_qFind(rhs, i));
4729 parent.arg_n = i + 1;
4730 }
4731}
4732
4733// --- command.acr_dm.arg.Setary2
4734// Copy specified array into arg, discarding previous contents.
4735// If the RHS argument aliases the array (refers to the same memory), throw exception.
4736void command::arg_Setary(command::acr_dm& parent, const algo::aryptr<algo::cstring> &rhs) {
4737 arg_RemoveAll(parent);
4738 arg_Addary(parent, rhs);
4739}
4740
4741// --- command.acr_dm.arg.AllocNVal
4742// Reserve space. Insert N elements at the end of the array, return pointer to array
4743algo::aryptr<algo::cstring> command::arg_AllocNVal(command::acr_dm& parent, int n_elems, const algo::cstring& val) {
4744 arg_Reserve(parent, n_elems);
4745 int old_n = parent.arg_n;
4746 int new_n = old_n + n_elems;
4747 algo::cstring *elems = parent.arg_elems;
4748 for (int i = old_n; i < new_n; i++) {
4749 new (elems + i) algo::cstring(val);
4750 }
4751 parent.arg_n = new_n;
4752 return algo::aryptr<algo::cstring>(elems + old_n, n_elems);
4753}
4754
4755// --- command.acr_dm.arg.ReadStrptrMaybe
4756// A single element is read from input string and appended to the array.
4757// If the string contains an error, the array is untouched.
4758// Function returns success value.
4759bool command::arg_ReadStrptrMaybe(command::acr_dm& parent, algo::strptr in_str) {
4760 bool retval = true;
4761 algo::cstring &elem = arg_Alloc(parent);
4762 retval = algo::cstring_ReadStrptrMaybe(elem, in_str);
4763 if (!retval) {
4764 arg_RemoveLast(parent);
4765 }
4766 return retval;
4767}
4768
4769// --- command.acr_dm..ReadFieldMaybe
4770bool command::acr_dm_ReadFieldMaybe(command::acr_dm& parent, algo::strptr field, algo::strptr strval) {
4771 bool retval = true;
4772 command::FieldId field_id;
4773 (void)value_SetStrptrMaybe(field_id,algo::Pathcomp(field, ".LL"));
4774 switch(field_id) {
4775 case command_FieldId_in: {
4776 retval = algo::cstring_ReadStrptrMaybe(parent.in, strval);
4777 break;
4778 }
4779 case command_FieldId_arg: {
4780 retval = arg_ReadStrptrMaybe(parent, strval);
4781 break;
4782 }
4783 case command_FieldId_write_ours: {
4784 retval = bool_ReadStrptrMaybe(parent.write_ours, strval);
4785 break;
4786 }
4787 case command_FieldId_msize: {
4788 retval = u8_ReadStrptrMaybe(parent.msize, strval);
4789 break;
4790 }
4791 case command_FieldId_rowid: {
4792 retval = bool_ReadStrptrMaybe(parent.rowid, strval);
4793 break;
4794 }
4795 default: break;
4796 }
4797 if (!retval) {
4798 algo_lib::AppendErrtext("attr",field);
4799 }
4800 return retval;
4801}
4802
4803// --- command.acr_dm..ReadTupleMaybe
4804// Read fields of command::acr_dm from attributes of ascii tuple TUPLE
4805bool command::acr_dm_ReadTupleMaybe(command::acr_dm &parent, algo::Tuple &tuple) {
4806 bool retval = true;
4807 int anon_idx = 0;
4808 ind_beg(algo::Tuple_attrs_curs,attr,tuple) {
4809 if (ch_N(attr.name) == 0) {
4810 attr.name = acr_dm_GetAnon(parent, anon_idx++);
4811 }
4812 retval = acr_dm_ReadFieldMaybe(parent, attr.name, attr.value);
4813 if (!retval) {
4814 break;
4815 }
4816 }ind_end;
4817 return retval;
4818}
4819
4820// --- command.acr_dm..Uninit
4821void command::acr_dm_Uninit(command::acr_dm& parent) {
4822 command::acr_dm &row = parent; (void)row;
4823
4824 // command.acr_dm.arg.Uninit (Tary) //Files to merge: older ours theirs...
4825 // remove all elements from command.acr_dm.arg
4826 arg_RemoveAll(parent);
4827 // free memory for Tary command.acr_dm.arg
4828 algo_lib::malloc_FreeMem(parent.arg_elems, sizeof(algo::cstring)*parent.arg_max); // (command.acr_dm.arg)
4829}
4830
4831// --- command.acr_dm..ToCmdline
4832// Convenience function that returns a full command line
4833// Assume command is in a directory called bin
4834tempstr command::acr_dm_ToCmdline(command::acr_dm& row) {
4835 tempstr ret;
4836 ret << "bin/acr_dm ";
4837 acr_dm_PrintArgv(row, ret);
4838 // inherit less intense verbose, debug options
4839 for (int i = 1; i < algo_lib::_db.cmdline.verbose; i++) {
4840 ret << " -verbose";
4841 }
4842 for (int i = 1; i < algo_lib::_db.cmdline.debug; i++) {
4843 ret << " -debug";
4844 }
4845 return ret;
4846}
4847
4848// --- command.acr_dm..PrintArgv
4849// print string representation of ROW to string STR
4850// cfmt:command.acr_dm.Argv printfmt:Tuple
4851void command::acr_dm_PrintArgv(command::acr_dm& row, algo::cstring& str) {
4852 algo::tempstr temp;
4853 (void)temp;
4854 (void)str;
4855 if (!(row.in == "data")) {
4856 ch_RemoveAll(temp);
4857 cstring_Print(row.in, temp);
4858 str << " -in:";
4859 strptr_PrintBash(temp,str);
4860 }
4861 ind_beg(acr_dm_arg_curs,value,row) {
4862 ch_RemoveAll(temp);
4863 cstring_Print(value, temp);
4864 str << " -arg:";
4865 strptr_PrintBash(temp,str);
4866 }ind_end;
4867 if (!(row.write_ours == false)) {
4868 ch_RemoveAll(temp);
4869 bool_Print(row.write_ours, temp);
4870 str << " -write_ours:";
4871 strptr_PrintBash(temp,str);
4872 }
4873 if (!(row.msize == 7)) {
4874 ch_RemoveAll(temp);
4875 u8_Print(row.msize, temp);
4876 str << " -msize:";
4877 strptr_PrintBash(temp,str);
4878 }
4879 if (!(row.rowid == false)) {
4880 ch_RemoveAll(temp);
4881 bool_Print(row.rowid, temp);
4882 str << " -rowid:";
4883 strptr_PrintBash(temp,str);
4884 }
4885}
4886
4887// --- command.acr_dm..GetAnon
4888algo::strptr command::acr_dm_GetAnon(command::acr_dm &parent, i32 idx) {
4889 (void)parent;//only to avoid -Wunused-parameter
4890 switch(idx) {
4891 default: return strptr("arg", 3);
4892 }
4893}
4894
4895// --- command.acr_dm..NArgs
4896// Used with command lines
4897// Return # of command-line arguments that must follow this argument
4898// If FIELD is invalid, return -1
4899i32 command::acr_dm_NArgs(command::FieldId field, algo::strptr& out_dflt, bool* out_anon) {
4900 i32 retval = 1;
4901 switch (field) {
4902 case command_FieldId_in: { // $comment
4903 *out_anon = false;
4904 } break;
4905 case command_FieldId_arg: { // $comment
4906 *out_anon = true;
4907 } break;
4908 case command_FieldId_write_ours: { // $comment
4909 *out_anon = false;
4910 retval=0;
4911 out_dflt="Y";
4912 } break;
4913 case command_FieldId_msize: { // bool: no argument required but value may be specified as write_ours:Y
4914 *out_anon = false;
4915 } break;
4916 case command_FieldId_rowid: { // bool: no argument required but value may be specified as write_ours:Y
4917 *out_anon = false;
4918 retval=0;
4919 out_dflt="Y";
4920 } break;
4921 default:
4922 retval=-1; // unrecognized
4923 }
4924 return retval;
4925}
4926
4927// --- command.acr_dm_proc.acr_dm.Start
4928// Start subprocess
4929// If subprocess already running, do nothing. Otherwise, start it
4930int command::acr_dm_Start(command::acr_dm_proc& parent) {
4931 int retval = 0;
4932 if (parent.pid == 0) {
4933 verblog(acr_dm_ToCmdline(parent)); // maybe print command
4934#ifdef WIN32
4935 algo_lib::ResolveExecFname(parent.path);
4936 tempstr cmdline(acr_dm_ToCmdline(parent));
4937 parent.pid = dospawn(Zeroterm(parent.path),Zeroterm(cmdline),parent.timeout,parent.fstdin,parent.fstdout,parent.fstderr);
4938#else
4939 parent.pid = fork();
4940 if (parent.pid == 0) { // child
4941 algo_lib::DieWithParent();
4942 if (parent.timeout > 0) {
4943 alarm(parent.timeout);
4944 }
4945 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstdin , 0);
4946 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstdout, 1);
4947 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstderr, 2);
4948 if (retval==0) retval= acr_dm_Execv(parent);
4949 if (retval != 0) { // if start fails, print error
4950 int err=errno;
4951 prerr("command.acr_dm_execv"
4952 <<Keyval("errno",err)
4953 <<Keyval("errstr",strerror(err))
4954 <<Keyval("comment","Execv failed"));
4955 }
4956 _exit(127); // if failed to start, exit anyway
4957 } else if (parent.pid == -1) {
4958 retval = errno; // failed to fork
4959 }
4960#endif
4961 }
4962 parent.status = parent.pid > 0 ? 0 : -1; // if didn't start, set error status
4963 return retval;
4964}
4965
4966// --- command.acr_dm_proc.acr_dm.StartRead
4967// Start subprocess & Read output
4968algo::Fildes command::acr_dm_StartRead(command::acr_dm_proc& parent, algo_lib::FFildes &read) {
4969 int pipefd[2];
4970 int rc=pipe(pipefd);
4971 (void)rc;
4972 read.fd.value = pipefd[0];
4973 parent.fstdout << ">&" << pipefd[1];
4974 acr_dm_Start(parent);
4975 (void)close(pipefd[1]);
4976 return read.fd;
4977}
4978
4979// --- command.acr_dm_proc.acr_dm.Kill
4980// Kill subprocess and wait
4981void command::acr_dm_Kill(command::acr_dm_proc& parent) {
4982 if (parent.pid != 0) {
4983 kill(parent.pid,9);
4984 acr_dm_Wait(parent);
4985 }
4986}
4987
4988// --- command.acr_dm_proc.acr_dm.Wait
4989// Wait for subprocess to return
4990void command::acr_dm_Wait(command::acr_dm_proc& parent) {
4991 if (parent.pid > 0) {
4992 int wait_flags = 0;
4993 int wait_status = 0;
4994 int rc = -1;
4995 do {
4996 // really wait for subprocess to exit
4997 rc = waitpid(parent.pid,&wait_status,wait_flags);
4998 } while (rc==-1 && errno==EINTR);
4999 if (rc == parent.pid) {
5000 parent.status = wait_status;
5001 parent.pid = 0;
5002 }
5003 }
5004}
5005
5006// --- command.acr_dm_proc.acr_dm.Exec
5007// Start + Wait
5008// Execute subprocess and return exit code
5009int command::acr_dm_Exec(command::acr_dm_proc& parent) {
5010 acr_dm_Start(parent);
5011 acr_dm_Wait(parent);
5012 return parent.status;
5013}
5014
5015// --- command.acr_dm_proc.acr_dm.ExecX
5016// Start + Wait, throw exception on error
5017// Execute subprocess; throw human-readable exception on error
5018void command::acr_dm_ExecX(command::acr_dm_proc& parent) {
5019 int rc = acr_dm_Exec(parent);
5020 vrfy(rc==0, tempstr() << "algo_lib.exec" << Keyval("cmd",acr_dm_ToCmdline(parent))
5021 << Keyval("comment",algo::DescribeWaitStatus(parent.status)));
5022}
5023
5024// --- command.acr_dm_proc.acr_dm.Execv
5025// Call execv()
5026// Call execv with specified parameters
5027int command::acr_dm_Execv(command::acr_dm_proc& parent) {
5028 int ret = 0;
5029 algo::StringAry args;
5030 acr_dm_ToArgv(parent, args);
5031 char **argv = (char**)alloca((ary_N(args)+1)*sizeof(*argv));
5032 ind_beg(algo::StringAry_ary_curs,arg,args) {
5033 argv[ind_curs(arg).index] = Zeroterm(arg);
5034 }ind_end;
5035 argv[ary_N(args)] = NULL;
5036 // if parent.path is relative, search for it in PATH
5037 algo_lib::ResolveExecFname(parent.path);
5038 ret = execv(Zeroterm(parent.path),argv);
5039 return ret;
5040}
5041
5042// --- command.acr_dm_proc.acr_dm.ToCmdline
5043algo::tempstr command::acr_dm_ToCmdline(command::acr_dm_proc& parent) {
5044 algo::tempstr retval;
5045 retval << parent.path << " ";
5046 command::acr_dm_PrintArgv(parent.cmd,retval);
5047 if (ch_N(parent.fstdin)) {
5048 retval << " " << parent.fstdin;
5049 }
5050 if (ch_N(parent.fstdout)) {
5051 retval << " " << parent.fstdout;
5052 }
5053 if (ch_N(parent.fstderr)) {
5054 retval << " 2" << parent.fstderr;
5055 }
5056 return retval;
5057}
5058
5059// --- command.acr_dm_proc.acr_dm.ToArgv
5060// Form array from the command line
5061void command::acr_dm_ToArgv(command::acr_dm_proc& parent, algo::StringAry& args) {
5062 ary_RemoveAll(args);
5063 ary_Alloc(args) << parent.path;
5064
5065 if (parent.cmd.in != "data") {
5066 cstring *arg = &ary_Alloc(args);
5067 *arg << "-in:";
5068 cstring_Print(parent.cmd.in, *arg);
5069 }
5070 ind_beg(command::acr_dm_arg_curs,value,parent.cmd) {
5071 cstring *arg = &ary_Alloc(args);
5072 *arg << "-arg:";
5073 cstring_Print(value, *arg);
5074 }ind_end;
5075
5076 if (parent.cmd.write_ours != false) {
5077 cstring *arg = &ary_Alloc(args);
5078 *arg << "-write_ours:";
5079 bool_Print(parent.cmd.write_ours, *arg);
5080 }
5081
5082 if (parent.cmd.msize != 7) {
5083 cstring *arg = &ary_Alloc(args);
5084 *arg << "-msize:";
5085 u8_Print(parent.cmd.msize, *arg);
5086 }
5087
5088 if (parent.cmd.rowid != false) {
5089 cstring *arg = &ary_Alloc(args);
5090 *arg << "-rowid:";
5091 bool_Print(parent.cmd.rowid, *arg);
5092 }
5093 for (int i=1; i < algo_lib::_db.cmdline.verbose; ++i) {
5094 ary_Alloc(args) << "-verbose";
5095 }
5096}
5097
5098// --- command.acr_dm_proc..Uninit
5099void command::acr_dm_proc_Uninit(command::acr_dm_proc& parent) {
5100 command::acr_dm_proc &row = parent; (void)row;
5101
5102 // command.acr_dm_proc.acr_dm.Uninit (Exec) //
5103 acr_dm_Kill(parent); // kill child, ensure forward progress
5104}
5105
5106// --- command.acr_ed..ReadFieldMaybe
5107bool command::acr_ed_ReadFieldMaybe(command::acr_ed& parent, algo::strptr field, algo::strptr strval) {
5108 bool retval = true;
5109 command::FieldId field_id;
5110 (void)value_SetStrptrMaybe(field_id,field);
5111 switch(field_id) {
5112 case command_FieldId_in: {
5113 retval = algo::cstring_ReadStrptrMaybe(parent.in, strval);
5114 break;
5115 }
5116 case command_FieldId_create: {
5117 retval = bool_ReadStrptrMaybe(parent.create, strval);
5118 break;
5119 }
5120 case command_FieldId_del: {
5121 retval = bool_ReadStrptrMaybe(parent.del, strval);
5122 break;
5123 }
5124 case command_FieldId_rename: {
5125 retval = algo::cstring_ReadStrptrMaybe(parent.rename, strval);
5126 break;
5127 }
5128 case command_FieldId_finput: {
5129 retval = bool_ReadStrptrMaybe(parent.finput, strval);
5130 break;
5131 }
5132 case command_FieldId_foutput: {
5133 retval = bool_ReadStrptrMaybe(parent.foutput, strval);
5134 break;
5135 }
5136 case command_FieldId_srcfile: {
5137 retval = algo::cstring_ReadStrptrMaybe(parent.srcfile, strval);
5138 break;
5139 }
5140 case command_FieldId_gstatic: {
5141 retval = bool_ReadStrptrMaybe(parent.gstatic, strval);
5142 break;
5143 }
5144 case command_FieldId_indexed: {
5145 retval = bool_ReadStrptrMaybe(parent.indexed, strval);
5146 break;
5147 }
5148 case command_FieldId_target: {
5149 retval = algo::Smallstr16_ReadStrptrMaybe(parent.target, strval);
5150 break;
5151 }
5152 case command_FieldId_nstype: {
5153 retval = algo::Smallstr50_ReadStrptrMaybe(parent.nstype, strval);
5154 break;
5155 }
5156 case command_FieldId_ctype: {
5157 retval = algo::Smallstr100_ReadStrptrMaybe(parent.ctype, strval);
5158 break;
5159 }
5160 case command_FieldId_pooltype: {
5161 retval = algo::Smallstr50_ReadStrptrMaybe(parent.pooltype, strval);
5162 break;
5163 }
5164 case command_FieldId_ssimfile: {
5165 retval = algo::Smallstr50_ReadStrptrMaybe(parent.ssimfile, strval);
5166 break;
5167 }
5168 case command_FieldId_subset: {
5169 retval = algo::Smallstr100_ReadStrptrMaybe(parent.subset, strval);
5170 break;
5171 }
5172 case command_FieldId_subset2: {
5173 retval = algo::Smallstr100_ReadStrptrMaybe(parent.subset2, strval);
5174 break;
5175 }
5176 case command_FieldId_separator: {
5177 retval = algo::cstring_ReadStrptrMaybe(parent.separator, strval);
5178 break;
5179 }
5180 case command_FieldId_field: {
5181 retval = algo::Smallstr100_ReadStrptrMaybe(parent.field, strval);
5182 break;
5183 }
5184 case command_FieldId_arg: {
5185 retval = algo::Smallstr100_ReadStrptrMaybe(parent.arg, strval);
5186 break;
5187 }
5188 case command_FieldId_dflt: {
5189 retval = algo::cstring_ReadStrptrMaybe(parent.dflt, strval);
5190 break;
5191 }
5192 case command_FieldId_anon: {
5193 retval = bool_ReadStrptrMaybe(parent.anon, strval);
5194 break;
5195 }
5196 case command_FieldId_bigend: {
5197 retval = bool_ReadStrptrMaybe(parent.bigend, strval);
5198 break;
5199 }
5200 case command_FieldId_cascdel: {
5201 retval = bool_ReadStrptrMaybe(parent.cascdel, strval);
5202 break;
5203 }
5204 case command_FieldId_before: {
5205 retval = algo::Smallstr100_ReadStrptrMaybe(parent.before, strval);
5206 break;
5207 }
5208 case command_FieldId_substr: {
5209 retval = algo::Smallstr100_ReadStrptrMaybe(parent.substr, strval);
5210 break;
5211 }
5212 case command_FieldId_alias: {
5213 retval = bool_ReadStrptrMaybe(parent.alias, strval);
5214 break;
5215 }
5216 case command_FieldId_srcfield: {
5217 retval = algo::Smallstr100_ReadStrptrMaybe(parent.srcfield, strval);
5218 break;
5219 }
5220 case command_FieldId_fstep: {
5221 retval = algo::Smallstr100_ReadStrptrMaybe(parent.fstep, strval);
5222 break;
5223 }
5224 case command_FieldId_inscond: {
5225 retval = algo::cstring_ReadStrptrMaybe(parent.inscond, strval);
5226 break;
5227 }
5228 case command_FieldId_reftype: {
5229 retval = algo::Smallstr50_ReadStrptrMaybe(parent.reftype, strval);
5230 break;
5231 }
5232 case command_FieldId_hashfld: {
5233 retval = algo::Smallstr100_ReadStrptrMaybe(parent.hashfld, strval);
5234 break;
5235 }
5236 case command_FieldId_sortfld: {
5237 retval = algo::Smallstr100_ReadStrptrMaybe(parent.sortfld, strval);
5238 break;
5239 }
5240 case command_FieldId_unittest: {
5241 retval = algo::cstring_ReadStrptrMaybe(parent.unittest, strval);
5242 break;
5243 }
5244 case command_FieldId_citest: {
5245 retval = algo::cstring_ReadStrptrMaybe(parent.citest, strval);
5246 break;
5247 }
5248 case command_FieldId_cppfunc: {
5249 retval = algo::cstring_ReadStrptrMaybe(parent.cppfunc, strval);
5250 break;
5251 }
5252 case command_FieldId_xref: {
5253 retval = bool_ReadStrptrMaybe(parent.xref, strval);
5254 break;
5255 }
5256 case command_FieldId_via: {
5257 retval = algo::cstring_ReadStrptrMaybe(parent.via, strval);
5258 break;
5259 }
5260 case command_FieldId_write: {
5261 retval = bool_ReadStrptrMaybe(parent.write, strval);
5262 break;
5263 }
5264 case command_FieldId_e: {
5265 retval = bool_ReadStrptrMaybe(parent.e, strval);
5266 break;
5267 }
5268 case command_FieldId_comment: {
5269 retval = algo::cstring_ReadStrptrMaybe(parent.comment, strval);
5270 break;
5271 }
5272 case command_FieldId_sandbox: {
5273 retval = bool_ReadStrptrMaybe(parent.sandbox, strval);
5274 break;
5275 }
5276 case command_FieldId_test: {
5277 retval = bool_ReadStrptrMaybe(parent.test, strval);
5278 break;
5279 }
5280 case command_FieldId_showcpp: {
5281 retval = bool_ReadStrptrMaybe(parent.showcpp, strval);
5282 break;
5283 }
5284 case command_FieldId_msgtype: {
5285 retval = algo::cstring_ReadStrptrMaybe(parent.msgtype, strval);
5286 break;
5287 }
5288 case command_FieldId_anonfld: {
5289 retval = bool_ReadStrptrMaybe(parent.anonfld, strval);
5290 break;
5291 }
5292 default: break;
5293 }
5294 if (!retval) {
5295 algo_lib::AppendErrtext("attr",field);
5296 }
5297 return retval;
5298}
5299
5300// --- command.acr_ed..ReadTupleMaybe
5301// Read fields of command::acr_ed from attributes of ascii tuple TUPLE
5302bool command::acr_ed_ReadTupleMaybe(command::acr_ed &parent, algo::Tuple &tuple) {
5303 bool retval = true;
5304 ind_beg(algo::Tuple_attrs_curs,attr,tuple) {
5305 retval = acr_ed_ReadFieldMaybe(parent, attr.name, attr.value);
5306 if (!retval) {
5307 break;
5308 }
5309 }ind_end;
5310 return retval;
5311}
5312
5313// --- command.acr_ed..Init
5314// Set all fields to initial values.
5315void command::acr_ed_Init(command::acr_ed& parent) {
5316 parent.in = algo::strptr("data");
5317 parent.create = bool(false);
5318 parent.del = bool(false);
5319 parent.rename = algo::strptr("");
5320 parent.finput = bool(false);
5321 parent.foutput = bool(false);
5322 parent.srcfile = algo::strptr("");
5323 parent.gstatic = bool(false);
5324 parent.indexed = bool(false);
5325 parent.target = algo::strptr("");
5326 parent.nstype = algo::strptr("exe");
5327 parent.ctype = algo::strptr("");
5328 parent.pooltype = algo::strptr("");
5329 parent.ssimfile = algo::strptr("");
5330 parent.subset = algo::strptr("");
5331 parent.subset2 = algo::strptr("");
5332 parent.separator = algo::strptr(".");
5333 parent.field = algo::strptr("");
5334 parent.arg = algo::strptr("");
5335 parent.dflt = algo::strptr("");
5336 parent.anon = bool(false);
5337 parent.bigend = bool(false);
5338 parent.cascdel = bool(false);
5339 parent.before = algo::strptr("");
5340 parent.substr = algo::strptr("");
5341 parent.alias = bool(false);
5342 parent.srcfield = algo::strptr("");
5343 parent.fstep = algo::strptr("");
5344 parent.inscond = algo::strptr("true");
5345 parent.reftype = algo::strptr("");
5346 parent.hashfld = algo::strptr("");
5347 parent.sortfld = algo::strptr("");
5348 parent.unittest = algo::strptr("");
5349 parent.citest = algo::strptr("");
5350 parent.cppfunc = algo::strptr("");
5351 parent.xref = bool(false);
5352 parent.via = algo::strptr("");
5353 parent.write = bool(false);
5354 parent.e = bool(false);
5355 parent.comment = algo::strptr("");
5356 parent.sandbox = bool(false);
5357 parent.test = bool(false);
5358 parent.showcpp = bool(false);
5359 parent.msgtype = algo::strptr("");
5360 parent.anonfld = bool(false);
5361}
5362
5363// --- command.acr_ed..ToCmdline
5364// Convenience function that returns a full command line
5365// Assume command is in a directory called bin
5366tempstr command::acr_ed_ToCmdline(command::acr_ed& row) {
5367 tempstr ret;
5368 ret << "bin/acr_ed ";
5369 acr_ed_PrintArgv(row, ret);
5370 // inherit less intense verbose, debug options
5371 for (int i = 1; i < algo_lib::_db.cmdline.verbose; i++) {
5372 ret << " -verbose";
5373 }
5374 for (int i = 1; i < algo_lib::_db.cmdline.debug; i++) {
5375 ret << " -debug";
5376 }
5377 return ret;
5378}
5379
5380// --- command.acr_ed..PrintArgv
5381// print string representation of ROW to string STR
5382// cfmt:command.acr_ed.Argv printfmt:Auto
5383void command::acr_ed_PrintArgv(command::acr_ed& row, algo::cstring& str) {
5384 algo::tempstr temp;
5385 (void)temp;
5386 (void)str;
5387 if (!(row.in == "data")) {
5388 ch_RemoveAll(temp);
5389 cstring_Print(row.in, temp);
5390 str << " -in:";
5391 strptr_PrintBash(temp,str);
5392 }
5393 if (!(row.create == false)) {
5394 ch_RemoveAll(temp);
5395 bool_Print(row.create, temp);
5396 str << " -create:";
5397 strptr_PrintBash(temp,str);
5398 }
5399 if (!(row.del == false)) {
5400 ch_RemoveAll(temp);
5401 bool_Print(row.del, temp);
5402 str << " -del:";
5403 strptr_PrintBash(temp,str);
5404 }
5405 if (!(row.rename == "")) {
5406 ch_RemoveAll(temp);
5407 cstring_Print(row.rename, temp);
5408 str << " -rename:";
5409 strptr_PrintBash(temp,str);
5410 }
5411 if (!(row.finput == false)) {
5412 ch_RemoveAll(temp);
5413 bool_Print(row.finput, temp);
5414 str << " -finput:";
5415 strptr_PrintBash(temp,str);
5416 }
5417 if (!(row.foutput == false)) {
5418 ch_RemoveAll(temp);
5419 bool_Print(row.foutput, temp);
5420 str << " -foutput:";
5421 strptr_PrintBash(temp,str);
5422 }
5423 if (!(row.srcfile == "")) {
5424 ch_RemoveAll(temp);
5425 cstring_Print(row.srcfile, temp);
5426 str << " -srcfile:";
5427 strptr_PrintBash(temp,str);
5428 }
5429 if (!(row.gstatic == false)) {
5430 ch_RemoveAll(temp);
5431 bool_Print(row.gstatic, temp);
5432 str << " -gstatic:";
5433 strptr_PrintBash(temp,str);
5434 }
5435 if (!(row.indexed == false)) {
5436 ch_RemoveAll(temp);
5437 bool_Print(row.indexed, temp);
5438 str << " -indexed:";
5439 strptr_PrintBash(temp,str);
5440 }
5441 if (!(row.target == "")) {
5442 ch_RemoveAll(temp);
5443 Smallstr16_Print(row.target, temp);
5444 str << " -target:";
5445 strptr_PrintBash(temp,str);
5446 }
5447 if (!(row.nstype == "exe")) {
5448 ch_RemoveAll(temp);
5449 Smallstr50_Print(row.nstype, temp);
5450 str << " -nstype:";
5451 strptr_PrintBash(temp,str);
5452 }
5453 if (!(row.ctype == "")) {
5454 ch_RemoveAll(temp);
5455 Smallstr100_Print(row.ctype, temp);
5456 str << " -ctype:";
5457 strptr_PrintBash(temp,str);
5458 }
5459 if (!(row.pooltype == "")) {
5460 ch_RemoveAll(temp);
5461 Smallstr50_Print(row.pooltype, temp);
5462 str << " -pooltype:";
5463 strptr_PrintBash(temp,str);
5464 }
5465 if (!(row.ssimfile == "")) {
5466 ch_RemoveAll(temp);
5467 Smallstr50_Print(row.ssimfile, temp);
5468 str << " -ssimfile:";
5469 strptr_PrintBash(temp,str);
5470 }
5471 if (!(row.subset == "")) {
5472 ch_RemoveAll(temp);
5473 Smallstr100_Print(row.subset, temp);
5474 str << " -subset:";
5475 strptr_PrintBash(temp,str);
5476 }
5477 if (!(row.subset2 == "")) {
5478 ch_RemoveAll(temp);
5479 Smallstr100_Print(row.subset2, temp);
5480 str << " -subset2:";
5481 strptr_PrintBash(temp,str);
5482 }
5483 if (!(row.separator == ".")) {
5484 ch_RemoveAll(temp);
5485 cstring_Print(row.separator, temp);
5486 str << " -separator:";
5487 strptr_PrintBash(temp,str);
5488 }
5489 if (!(row.field == "")) {
5490 ch_RemoveAll(temp);
5491 Smallstr100_Print(row.field, temp);
5492 str << " -field:";
5493 strptr_PrintBash(temp,str);
5494 }
5495 if (!(row.arg == "")) {
5496 ch_RemoveAll(temp);
5497 Smallstr100_Print(row.arg, temp);
5498 str << " -arg:";
5499 strptr_PrintBash(temp,str);
5500 }
5501 if (!(row.dflt == "")) {
5502 ch_RemoveAll(temp);
5503 cstring_Print(row.dflt, temp);
5504 str << " -dflt:";
5505 strptr_PrintBash(temp,str);
5506 }
5507 if (!(row.anon == false)) {
5508 ch_RemoveAll(temp);
5509 bool_Print(row.anon, temp);
5510 str << " -anon:";
5511 strptr_PrintBash(temp,str);
5512 }
5513 if (!(row.bigend == false)) {
5514 ch_RemoveAll(temp);
5515 bool_Print(row.bigend, temp);
5516 str << " -bigend:";
5517 strptr_PrintBash(temp,str);
5518 }
5519 if (!(row.cascdel == false)) {
5520 ch_RemoveAll(temp);
5521 bool_Print(row.cascdel, temp);
5522 str << " -cascdel:";
5523 strptr_PrintBash(temp,str);
5524 }
5525 if (!(row.before == "")) {
5526 ch_RemoveAll(temp);
5527 Smallstr100_Print(row.before, temp);
5528 str << " -before:";
5529 strptr_PrintBash(temp,str);
5530 }
5531 if (!(row.substr == "")) {
5532 ch_RemoveAll(temp);
5533 Smallstr100_Print(row.substr, temp);
5534 str << " -substr:";
5535 strptr_PrintBash(temp,str);
5536 }
5537 if (!(row.alias == false)) {
5538 ch_RemoveAll(temp);
5539 bool_Print(row.alias, temp);
5540 str << " -alias:";
5541 strptr_PrintBash(temp,str);
5542 }
5543 if (!(row.srcfield == "")) {
5544 ch_RemoveAll(temp);
5545 Smallstr100_Print(row.srcfield, temp);
5546 str << " -srcfield:";
5547 strptr_PrintBash(temp,str);
5548 }
5549 if (!(row.fstep == "")) {
5550 ch_RemoveAll(temp);
5551 Smallstr100_Print(row.fstep, temp);
5552 str << " -fstep:";
5553 strptr_PrintBash(temp,str);
5554 }
5555 if (!(row.inscond == "true")) {
5556 ch_RemoveAll(temp);
5557 cstring_Print(row.inscond, temp);
5558 str << " -inscond:";
5559 strptr_PrintBash(temp,str);
5560 }
5561 if (!(row.reftype == "")) {
5562 ch_RemoveAll(temp);
5563 Smallstr50_Print(row.reftype, temp);
5564 str << " -reftype:";
5565 strptr_PrintBash(temp,str);
5566 }
5567 if (!(row.hashfld == "")) {
5568 ch_RemoveAll(temp);
5569 Smallstr100_Print(row.hashfld, temp);
5570 str << " -hashfld:";
5571 strptr_PrintBash(temp,str);
5572 }
5573 if (!(row.sortfld == "")) {
5574 ch_RemoveAll(temp);
5575 Smallstr100_Print(row.sortfld, temp);
5576 str << " -sortfld:";
5577 strptr_PrintBash(temp,str);
5578 }
5579 if (!(row.unittest == "")) {
5580 ch_RemoveAll(temp);
5581 cstring_Print(row.unittest, temp);
5582 str << " -unittest:";
5583 strptr_PrintBash(temp,str);
5584 }
5585 if (!(row.citest == "")) {
5586 ch_RemoveAll(temp);
5587 cstring_Print(row.citest, temp);
5588 str << " -citest:";
5589 strptr_PrintBash(temp,str);
5590 }
5591 if (!(row.cppfunc == "")) {
5592 ch_RemoveAll(temp);
5593 cstring_Print(row.cppfunc, temp);
5594 str << " -cppfunc:";
5595 strptr_PrintBash(temp,str);
5596 }
5597 if (!(row.xref == false)) {
5598 ch_RemoveAll(temp);
5599 bool_Print(row.xref, temp);
5600 str << " -xref:";
5601 strptr_PrintBash(temp,str);
5602 }
5603 if (!(row.via == "")) {
5604 ch_RemoveAll(temp);
5605 cstring_Print(row.via, temp);
5606 str << " -via:";
5607 strptr_PrintBash(temp,str);
5608 }
5609 if (!(row.write == false)) {
5610 ch_RemoveAll(temp);
5611 bool_Print(row.write, temp);
5612 str << " -write:";
5613 strptr_PrintBash(temp,str);
5614 }
5615 if (!(row.e == false)) {
5616 ch_RemoveAll(temp);
5617 bool_Print(row.e, temp);
5618 str << " -e:";
5619 strptr_PrintBash(temp,str);
5620 }
5621 if (!(row.comment == "")) {
5622 ch_RemoveAll(temp);
5623 cstring_Print(row.comment, temp);
5624 str << " -comment:";
5625 strptr_PrintBash(temp,str);
5626 }
5627 if (!(row.sandbox == false)) {
5628 ch_RemoveAll(temp);
5629 bool_Print(row.sandbox, temp);
5630 str << " -sandbox:";
5631 strptr_PrintBash(temp,str);
5632 }
5633 if (!(row.test == false)) {
5634 ch_RemoveAll(temp);
5635 bool_Print(row.test, temp);
5636 str << " -test:";
5637 strptr_PrintBash(temp,str);
5638 }
5639 if (!(row.showcpp == false)) {
5640 ch_RemoveAll(temp);
5641 bool_Print(row.showcpp, temp);
5642 str << " -showcpp:";
5643 strptr_PrintBash(temp,str);
5644 }
5645 if (!(row.msgtype == "")) {
5646 ch_RemoveAll(temp);
5647 cstring_Print(row.msgtype, temp);
5648 str << " -msgtype:";
5649 strptr_PrintBash(temp,str);
5650 }
5651 if (!(row.anonfld == false)) {
5652 ch_RemoveAll(temp);
5653 bool_Print(row.anonfld, temp);
5654 str << " -anonfld:";
5655 strptr_PrintBash(temp,str);
5656 }
5657}
5658
5659// --- command.acr_ed..NArgs
5660// Used with command lines
5661// Return # of command-line arguments that must follow this argument
5662// If FIELD is invalid, return -1
5663i32 command::acr_ed_NArgs(command::FieldId field, algo::strptr& out_dflt, bool* out_anon) {
5664 i32 retval = 1;
5665 switch (field) {
5666 case command_FieldId_in: { // $comment
5667 *out_anon = false;
5668 } break;
5669 case command_FieldId_create: { // $comment
5670 *out_anon = false;
5671 retval=0;
5672 out_dflt="Y";
5673 } break;
5674 case command_FieldId_del: { // bool: no argument required but value may be specified as create:Y
5675 *out_anon = false;
5676 retval=0;
5677 out_dflt="Y";
5678 } break;
5679 case command_FieldId_rename: { // bool: no argument required but value may be specified as del:Y
5680 *out_anon = false;
5681 } break;
5682 case command_FieldId_finput: { // bool: no argument required but value may be specified as del:Y
5683 *out_anon = false;
5684 retval=0;
5685 out_dflt="Y";
5686 } break;
5687 case command_FieldId_foutput: { // bool: no argument required but value may be specified as finput:Y
5688 *out_anon = false;
5689 retval=0;
5690 out_dflt="Y";
5691 } break;
5692 case command_FieldId_srcfile: { // bool: no argument required but value may be specified as foutput:Y
5693 *out_anon = false;
5694 } break;
5695 case command_FieldId_gstatic: { // bool: no argument required but value may be specified as foutput:Y
5696 *out_anon = false;
5697 retval=0;
5698 out_dflt="Y";
5699 } break;
5700 case command_FieldId_indexed: { // bool: no argument required but value may be specified as gstatic:Y
5701 *out_anon = false;
5702 retval=0;
5703 out_dflt="Y";
5704 } break;
5705 case command_FieldId_target: { // bool: no argument required but value may be specified as indexed:Y
5706 *out_anon = false;
5707 } break;
5708 case command_FieldId_nstype: { // bool: no argument required but value may be specified as indexed:Y
5709 *out_anon = false;
5710 } break;
5711 case command_FieldId_ctype: { // bool: no argument required but value may be specified as indexed:Y
5712 *out_anon = false;
5713 } break;
5714 case command_FieldId_pooltype: { // bool: no argument required but value may be specified as indexed:Y
5715 *out_anon = false;
5716 } break;
5717 case command_FieldId_ssimfile: { // bool: no argument required but value may be specified as indexed:Y
5718 *out_anon = false;
5719 } break;
5720 case command_FieldId_subset: { // bool: no argument required but value may be specified as indexed:Y
5721 *out_anon = false;
5722 } break;
5723 case command_FieldId_subset2: { // bool: no argument required but value may be specified as indexed:Y
5724 *out_anon = false;
5725 } break;
5726 case command_FieldId_separator: { // bool: no argument required but value may be specified as indexed:Y
5727 *out_anon = false;
5728 } break;
5729 case command_FieldId_field: { // bool: no argument required but value may be specified as indexed:Y
5730 *out_anon = false;
5731 } break;
5732 case command_FieldId_arg: { // bool: no argument required but value may be specified as indexed:Y
5733 *out_anon = false;
5734 } break;
5735 case command_FieldId_dflt: { // bool: no argument required but value may be specified as indexed:Y
5736 *out_anon = false;
5737 } break;
5738 case command_FieldId_anon: { // bool: no argument required but value may be specified as indexed:Y
5739 *out_anon = false;
5740 retval=0;
5741 out_dflt="Y";
5742 } break;
5743 case command_FieldId_bigend: { // bool: no argument required but value may be specified as anon:Y
5744 *out_anon = false;
5745 retval=0;
5746 out_dflt="Y";
5747 } break;
5748 case command_FieldId_cascdel: { // bool: no argument required but value may be specified as bigend:Y
5749 *out_anon = false;
5750 retval=0;
5751 out_dflt="Y";
5752 } break;
5753 case command_FieldId_before: { // bool: no argument required but value may be specified as cascdel:Y
5754 *out_anon = false;
5755 } break;
5756 case command_FieldId_substr: { // bool: no argument required but value may be specified as cascdel:Y
5757 *out_anon = false;
5758 } break;
5759 case command_FieldId_alias: { // bool: no argument required but value may be specified as cascdel:Y
5760 *out_anon = false;
5761 retval=0;
5762 out_dflt="Y";
5763 } break;
5764 case command_FieldId_srcfield: { // bool: no argument required but value may be specified as alias:Y
5765 *out_anon = false;
5766 } break;
5767 case command_FieldId_fstep: { // bool: no argument required but value may be specified as alias:Y
5768 *out_anon = false;
5769 } break;
5770 case command_FieldId_inscond: { // bool: no argument required but value may be specified as alias:Y
5771 *out_anon = false;
5772 } break;
5773 case command_FieldId_reftype: { // bool: no argument required but value may be specified as alias:Y
5774 *out_anon = false;
5775 } break;
5776 case command_FieldId_hashfld: { // bool: no argument required but value may be specified as alias:Y
5777 *out_anon = false;
5778 } break;
5779 case command_FieldId_sortfld: { // bool: no argument required but value may be specified as alias:Y
5780 *out_anon = false;
5781 } break;
5782 case command_FieldId_unittest: { // bool: no argument required but value may be specified as alias:Y
5783 *out_anon = false;
5784 } break;
5785 case command_FieldId_citest: { // bool: no argument required but value may be specified as alias:Y
5786 *out_anon = false;
5787 } break;
5788 case command_FieldId_cppfunc: { // bool: no argument required but value may be specified as alias:Y
5789 *out_anon = false;
5790 } break;
5791 case command_FieldId_xref: { // bool: no argument required but value may be specified as alias:Y
5792 *out_anon = false;
5793 retval=0;
5794 out_dflt="Y";
5795 } break;
5796 case command_FieldId_via: { // bool: no argument required but value may be specified as xref:Y
5797 *out_anon = false;
5798 } break;
5799 case command_FieldId_write: { // bool: no argument required but value may be specified as xref:Y
5800 *out_anon = false;
5801 retval=0;
5802 out_dflt="Y";
5803 } break;
5804 case command_FieldId_e: { // bool: no argument required but value may be specified as write:Y
5805 *out_anon = false;
5806 retval=0;
5807 out_dflt="Y";
5808 } break;
5809 case command_FieldId_comment: { // bool: no argument required but value may be specified as e:Y
5810 *out_anon = false;
5811 } break;
5812 case command_FieldId_sandbox: { // bool: no argument required but value may be specified as e:Y
5813 *out_anon = false;
5814 retval=0;
5815 out_dflt="Y";
5816 } break;
5817 case command_FieldId_test: { // bool: no argument required but value may be specified as sandbox:Y
5818 *out_anon = false;
5819 retval=0;
5820 out_dflt="Y";
5821 } break;
5822 case command_FieldId_showcpp: { // bool: no argument required but value may be specified as test:Y
5823 *out_anon = false;
5824 retval=0;
5825 out_dflt="Y";
5826 } break;
5827 case command_FieldId_msgtype: { // bool: no argument required but value may be specified as showcpp:Y
5828 *out_anon = false;
5829 } break;
5830 case command_FieldId_anonfld: { // bool: no argument required but value may be specified as showcpp:Y
5831 *out_anon = false;
5832 retval=0;
5833 out_dflt="Y";
5834 } break;
5835 default:
5836 retval=-1; // unrecognized
5837 }
5838 return retval;
5839}
5840
5841// --- command.acr_ed_proc.acr_ed.Start
5842// Start subprocess
5843// If subprocess already running, do nothing. Otherwise, start it
5844int command::acr_ed_Start(command::acr_ed_proc& parent) {
5845 int retval = 0;
5846 if (parent.pid == 0) {
5847 verblog(acr_ed_ToCmdline(parent)); // maybe print command
5848#ifdef WIN32
5849 algo_lib::ResolveExecFname(parent.path);
5850 tempstr cmdline(acr_ed_ToCmdline(parent));
5851 parent.pid = dospawn(Zeroterm(parent.path),Zeroterm(cmdline),parent.timeout,parent.fstdin,parent.fstdout,parent.fstderr);
5852#else
5853 parent.pid = fork();
5854 if (parent.pid == 0) { // child
5855 algo_lib::DieWithParent();
5856 if (parent.timeout > 0) {
5857 alarm(parent.timeout);
5858 }
5859 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstdin , 0);
5860 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstdout, 1);
5861 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstderr, 2);
5862 if (retval==0) retval= acr_ed_Execv(parent);
5863 if (retval != 0) { // if start fails, print error
5864 int err=errno;
5865 prerr("command.acr_ed_execv"
5866 <<Keyval("errno",err)
5867 <<Keyval("errstr",strerror(err))
5868 <<Keyval("comment","Execv failed"));
5869 }
5870 _exit(127); // if failed to start, exit anyway
5871 } else if (parent.pid == -1) {
5872 retval = errno; // failed to fork
5873 }
5874#endif
5875 }
5876 parent.status = parent.pid > 0 ? 0 : -1; // if didn't start, set error status
5877 return retval;
5878}
5879
5880// --- command.acr_ed_proc.acr_ed.StartRead
5881// Start subprocess & Read output
5882algo::Fildes command::acr_ed_StartRead(command::acr_ed_proc& parent, algo_lib::FFildes &read) {
5883 int pipefd[2];
5884 int rc=pipe(pipefd);
5885 (void)rc;
5886 read.fd.value = pipefd[0];
5887 parent.fstdout << ">&" << pipefd[1];
5888 acr_ed_Start(parent);
5889 (void)close(pipefd[1]);
5890 return read.fd;
5891}
5892
5893// --- command.acr_ed_proc.acr_ed.Kill
5894// Kill subprocess and wait
5895void command::acr_ed_Kill(command::acr_ed_proc& parent) {
5896 if (parent.pid != 0) {
5897 kill(parent.pid,9);
5898 acr_ed_Wait(parent);
5899 }
5900}
5901
5902// --- command.acr_ed_proc.acr_ed.Wait
5903// Wait for subprocess to return
5904void command::acr_ed_Wait(command::acr_ed_proc& parent) {
5905 if (parent.pid > 0) {
5906 int wait_flags = 0;
5907 int wait_status = 0;
5908 int rc = -1;
5909 do {
5910 // really wait for subprocess to exit
5911 rc = waitpid(parent.pid,&wait_status,wait_flags);
5912 } while (rc==-1 && errno==EINTR);
5913 if (rc == parent.pid) {
5914 parent.status = wait_status;
5915 parent.pid = 0;
5916 }
5917 }
5918}
5919
5920// --- command.acr_ed_proc.acr_ed.Exec
5921// Start + Wait
5922// Execute subprocess and return exit code
5923int command::acr_ed_Exec(command::acr_ed_proc& parent) {
5924 acr_ed_Start(parent);
5925 acr_ed_Wait(parent);
5926 return parent.status;
5927}
5928
5929// --- command.acr_ed_proc.acr_ed.ExecX
5930// Start + Wait, throw exception on error
5931// Execute subprocess; throw human-readable exception on error
5932void command::acr_ed_ExecX(command::acr_ed_proc& parent) {
5933 int rc = acr_ed_Exec(parent);
5934 vrfy(rc==0, tempstr() << "algo_lib.exec" << Keyval("cmd",acr_ed_ToCmdline(parent))
5935 << Keyval("comment",algo::DescribeWaitStatus(parent.status)));
5936}
5937
5938// --- command.acr_ed_proc.acr_ed.Execv
5939// Call execv()
5940// Call execv with specified parameters
5941int command::acr_ed_Execv(command::acr_ed_proc& parent) {
5942 int ret = 0;
5943 algo::StringAry args;
5944 acr_ed_ToArgv(parent, args);
5945 char **argv = (char**)alloca((ary_N(args)+1)*sizeof(*argv));
5946 ind_beg(algo::StringAry_ary_curs,arg,args) {
5947 argv[ind_curs(arg).index] = Zeroterm(arg);
5948 }ind_end;
5949 argv[ary_N(args)] = NULL;
5950 // if parent.path is relative, search for it in PATH
5951 algo_lib::ResolveExecFname(parent.path);
5952 ret = execv(Zeroterm(parent.path),argv);
5953 return ret;
5954}
5955
5956// --- command.acr_ed_proc.acr_ed.ToCmdline
5957algo::tempstr command::acr_ed_ToCmdline(command::acr_ed_proc& parent) {
5958 algo::tempstr retval;
5959 retval << parent.path << " ";
5960 command::acr_ed_PrintArgv(parent.cmd,retval);
5961 if (ch_N(parent.fstdin)) {
5962 retval << " " << parent.fstdin;
5963 }
5964 if (ch_N(parent.fstdout)) {
5965 retval << " " << parent.fstdout;
5966 }
5967 if (ch_N(parent.fstderr)) {
5968 retval << " 2" << parent.fstderr;
5969 }
5970 return retval;
5971}
5972
5973// --- command.acr_ed_proc.acr_ed.ToArgv
5974// Form array from the command line
5975void command::acr_ed_ToArgv(command::acr_ed_proc& parent, algo::StringAry& args) {
5976 ary_RemoveAll(args);
5977 ary_Alloc(args) << parent.path;
5978
5979 if (parent.cmd.in != "data") {
5980 cstring *arg = &ary_Alloc(args);
5981 *arg << "-in:";
5982 cstring_Print(parent.cmd.in, *arg);
5983 }
5984
5985 if (parent.cmd.create != false) {
5986 cstring *arg = &ary_Alloc(args);
5987 *arg << "-create:";
5988 bool_Print(parent.cmd.create, *arg);
5989 }
5990
5991 if (parent.cmd.del != false) {
5992 cstring *arg = &ary_Alloc(args);
5993 *arg << "-del:";
5994 bool_Print(parent.cmd.del, *arg);
5995 }
5996
5997 if (parent.cmd.rename != "") {
5998 cstring *arg = &ary_Alloc(args);
5999 *arg << "-rename:";
6000 cstring_Print(parent.cmd.rename, *arg);
6001 }
6002
6003 if (parent.cmd.finput != false) {
6004 cstring *arg = &ary_Alloc(args);
6005 *arg << "-finput:";
6006 bool_Print(parent.cmd.finput, *arg);
6007 }
6008
6009 if (parent.cmd.foutput != false) {
6010 cstring *arg = &ary_Alloc(args);
6011 *arg << "-foutput:";
6012 bool_Print(parent.cmd.foutput, *arg);
6013 }
6014
6015 if (parent.cmd.srcfile != "") {
6016 cstring *arg = &ary_Alloc(args);
6017 *arg << "-srcfile:";
6018 cstring_Print(parent.cmd.srcfile, *arg);
6019 }
6020
6021 if (parent.cmd.gstatic != false) {
6022 cstring *arg = &ary_Alloc(args);
6023 *arg << "-gstatic:";
6024 bool_Print(parent.cmd.gstatic, *arg);
6025 }
6026
6027 if (parent.cmd.indexed != false) {
6028 cstring *arg = &ary_Alloc(args);
6029 *arg << "-indexed:";
6030 bool_Print(parent.cmd.indexed, *arg);
6031 }
6032
6033 if (parent.cmd.target != "") {
6034 cstring *arg = &ary_Alloc(args);
6035 *arg << "-target:";
6036 Smallstr16_Print(parent.cmd.target, *arg);
6037 }
6038
6039 if (parent.cmd.nstype != "exe") {
6040 cstring *arg = &ary_Alloc(args);
6041 *arg << "-nstype:";
6042 Smallstr50_Print(parent.cmd.nstype, *arg);
6043 }
6044
6045 if (parent.cmd.ctype != "") {
6046 cstring *arg = &ary_Alloc(args);
6047 *arg << "-ctype:";
6048 Smallstr100_Print(parent.cmd.ctype, *arg);
6049 }
6050
6051 if (parent.cmd.pooltype != "") {
6052 cstring *arg = &ary_Alloc(args);
6053 *arg << "-pooltype:";
6054 Smallstr50_Print(parent.cmd.pooltype, *arg);
6055 }
6056
6057 if (parent.cmd.ssimfile != "") {
6058 cstring *arg = &ary_Alloc(args);
6059 *arg << "-ssimfile:";
6060 Smallstr50_Print(parent.cmd.ssimfile, *arg);
6061 }
6062
6063 if (parent.cmd.subset != "") {
6064 cstring *arg = &ary_Alloc(args);
6065 *arg << "-subset:";
6066 Smallstr100_Print(parent.cmd.subset, *arg);
6067 }
6068
6069 if (parent.cmd.subset2 != "") {
6070 cstring *arg = &ary_Alloc(args);
6071 *arg << "-subset2:";
6072 Smallstr100_Print(parent.cmd.subset2, *arg);
6073 }
6074
6075 if (parent.cmd.separator != ".") {
6076 cstring *arg = &ary_Alloc(args);
6077 *arg << "-separator:";
6078 cstring_Print(parent.cmd.separator, *arg);
6079 }
6080
6081 if (parent.cmd.field != "") {
6082 cstring *arg = &ary_Alloc(args);
6083 *arg << "-field:";
6084 Smallstr100_Print(parent.cmd.field, *arg);
6085 }
6086
6087 if (parent.cmd.arg != "") {
6088 cstring *arg = &ary_Alloc(args);
6089 *arg << "-arg:";
6090 Smallstr100_Print(parent.cmd.arg, *arg);
6091 }
6092
6093 if (parent.cmd.dflt != "") {
6094 cstring *arg = &ary_Alloc(args);
6095 *arg << "-dflt:";
6096 cstring_Print(parent.cmd.dflt, *arg);
6097 }
6098
6099 if (parent.cmd.anon != false) {
6100 cstring *arg = &ary_Alloc(args);
6101 *arg << "-anon:";
6102 bool_Print(parent.cmd.anon, *arg);
6103 }
6104
6105 if (parent.cmd.bigend != false) {
6106 cstring *arg = &ary_Alloc(args);
6107 *arg << "-bigend:";
6108 bool_Print(parent.cmd.bigend, *arg);
6109 }
6110
6111 if (parent.cmd.cascdel != false) {
6112 cstring *arg = &ary_Alloc(args);
6113 *arg << "-cascdel:";
6114 bool_Print(parent.cmd.cascdel, *arg);
6115 }
6116
6117 if (parent.cmd.before != "") {
6118 cstring *arg = &ary_Alloc(args);
6119 *arg << "-before:";
6120 Smallstr100_Print(parent.cmd.before, *arg);
6121 }
6122
6123 if (parent.cmd.substr != "") {
6124 cstring *arg = &ary_Alloc(args);
6125 *arg << "-substr:";
6126 Smallstr100_Print(parent.cmd.substr, *arg);
6127 }
6128
6129 if (parent.cmd.alias != false) {
6130 cstring *arg = &ary_Alloc(args);
6131 *arg << "-alias:";
6132 bool_Print(parent.cmd.alias, *arg);
6133 }
6134
6135 if (parent.cmd.srcfield != "") {
6136 cstring *arg = &ary_Alloc(args);
6137 *arg << "-srcfield:";
6138 Smallstr100_Print(parent.cmd.srcfield, *arg);
6139 }
6140
6141 if (parent.cmd.fstep != "") {
6142 cstring *arg = &ary_Alloc(args);
6143 *arg << "-fstep:";
6144 Smallstr100_Print(parent.cmd.fstep, *arg);
6145 }
6146
6147 if (parent.cmd.inscond != "true") {
6148 cstring *arg = &ary_Alloc(args);
6149 *arg << "-inscond:";
6150 cstring_Print(parent.cmd.inscond, *arg);
6151 }
6152
6153 if (parent.cmd.reftype != "") {
6154 cstring *arg = &ary_Alloc(args);
6155 *arg << "-reftype:";
6156 Smallstr50_Print(parent.cmd.reftype, *arg);
6157 }
6158
6159 if (parent.cmd.hashfld != "") {
6160 cstring *arg = &ary_Alloc(args);
6161 *arg << "-hashfld:";
6162 Smallstr100_Print(parent.cmd.hashfld, *arg);
6163 }
6164
6165 if (parent.cmd.sortfld != "") {
6166 cstring *arg = &ary_Alloc(args);
6167 *arg << "-sortfld:";
6168 Smallstr100_Print(parent.cmd.sortfld, *arg);
6169 }
6170
6171 if (parent.cmd.unittest != "") {
6172 cstring *arg = &ary_Alloc(args);
6173 *arg << "-unittest:";
6174 cstring_Print(parent.cmd.unittest, *arg);
6175 }
6176
6177 if (parent.cmd.citest != "") {
6178 cstring *arg = &ary_Alloc(args);
6179 *arg << "-citest:";
6180 cstring_Print(parent.cmd.citest, *arg);
6181 }
6182
6183 if (parent.cmd.cppfunc != "") {
6184 cstring *arg = &ary_Alloc(args);
6185 *arg << "-cppfunc:";
6186 cstring_Print(parent.cmd.cppfunc, *arg);
6187 }
6188
6189 if (parent.cmd.xref != false) {
6190 cstring *arg = &ary_Alloc(args);
6191 *arg << "-xref:";
6192 bool_Print(parent.cmd.xref, *arg);
6193 }
6194
6195 if (parent.cmd.via != "") {
6196 cstring *arg = &ary_Alloc(args);
6197 *arg << "-via:";
6198 cstring_Print(parent.cmd.via, *arg);
6199 }
6200
6201 if (parent.cmd.write != false) {
6202 cstring *arg = &ary_Alloc(args);
6203 *arg << "-write:";
6204 bool_Print(parent.cmd.write, *arg);
6205 }
6206
6207 if (parent.cmd.e != false) {
6208 cstring *arg = &ary_Alloc(args);
6209 *arg << "-e:";
6210 bool_Print(parent.cmd.e, *arg);
6211 }
6212
6213 if (parent.cmd.comment != "") {
6214 cstring *arg = &ary_Alloc(args);
6215 *arg << "-comment:";
6216 cstring_Print(parent.cmd.comment, *arg);
6217 }
6218
6219 if (parent.cmd.sandbox != false) {
6220 cstring *arg = &ary_Alloc(args);
6221 *arg << "-sandbox:";
6222 bool_Print(parent.cmd.sandbox, *arg);
6223 }
6224
6225 if (parent.cmd.test != false) {
6226 cstring *arg = &ary_Alloc(args);
6227 *arg << "-test:";
6228 bool_Print(parent.cmd.test, *arg);
6229 }
6230
6231 if (parent.cmd.showcpp != false) {
6232 cstring *arg = &ary_Alloc(args);
6233 *arg << "-showcpp:";
6234 bool_Print(parent.cmd.showcpp, *arg);
6235 }
6236
6237 if (parent.cmd.msgtype != "") {
6238 cstring *arg = &ary_Alloc(args);
6239 *arg << "-msgtype:";
6240 cstring_Print(parent.cmd.msgtype, *arg);
6241 }
6242
6243 if (parent.cmd.anonfld != false) {
6244 cstring *arg = &ary_Alloc(args);
6245 *arg << "-anonfld:";
6246 bool_Print(parent.cmd.anonfld, *arg);
6247 }
6248 for (int i=1; i < algo_lib::_db.cmdline.verbose; ++i) {
6249 ary_Alloc(args) << "-verbose";
6250 }
6251}
6252
6253// --- command.acr_ed_proc..Uninit
6254void command::acr_ed_proc_Uninit(command::acr_ed_proc& parent) {
6255 command::acr_ed_proc &row = parent; (void)row;
6256
6257 // command.acr_ed_proc.acr_ed.Uninit (Exec) //
6258 acr_ed_Kill(parent); // kill child, ensure forward progress
6259}
6260
6261// --- command.acr_in.ns.Print
6262// Print back to string
6263void command::ns_Print(command::acr_in& parent, algo::cstring &out) {
6264 Regx_Print(parent.ns, out);
6265}
6266
6267// --- command.acr_in.ns.ReadStrptrMaybe
6268// Read Regx from string
6269// Convert string to field. Return success value
6270bool command::ns_ReadStrptrMaybe(command::acr_in& parent, algo::strptr in) {
6271 bool retval = true;
6272 Regx_ReadSql(parent.ns, in, true);
6273 return retval;
6274}
6275
6276// --- command.acr_in.notssimfile.Print
6277// Print back to string
6278void command::notssimfile_Print(command::acr_in& parent, algo::cstring &out) {
6279 Regx_Print(parent.notssimfile, out);
6280}
6281
6282// --- command.acr_in.notssimfile.ReadStrptrMaybe
6283// Read Regx from string
6284// Convert string to field. Return success value
6285bool command::notssimfile_ReadStrptrMaybe(command::acr_in& parent, algo::strptr in) {
6286 bool retval = true;
6287 Regx_ReadSql(parent.notssimfile, in, true);
6288 return retval;
6289}
6290
6291// --- command.acr_in.r.Print
6292// Print back to string
6293void command::r_Print(command::acr_in& parent, algo::cstring &out) {
6294 Regx_Print(parent.r, out);
6295}
6296
6297// --- command.acr_in.r.ReadStrptrMaybe
6298// Read Regx from string
6299// Convert string to field. Return success value
6300bool command::r_ReadStrptrMaybe(command::acr_in& parent, algo::strptr in) {
6301 bool retval = true;
6302 Regx_ReadSql(parent.r, in, true);
6303 return retval;
6304}
6305
6306// --- command.acr_in..ReadFieldMaybe
6307bool command::acr_in_ReadFieldMaybe(command::acr_in& parent, algo::strptr field, algo::strptr strval) {
6308 bool retval = true;
6309 command::FieldId field_id;
6310 (void)value_SetStrptrMaybe(field_id,field);
6311 switch(field_id) {
6312 case command_FieldId_ns: {
6313 retval = ns_ReadStrptrMaybe(parent, strval);
6314 break;
6315 }
6316 case command_FieldId_data: {
6317 retval = bool_ReadStrptrMaybe(parent.data, strval);
6318 break;
6319 }
6320 case command_FieldId_sigcheck: {
6321 retval = bool_ReadStrptrMaybe(parent.sigcheck, strval);
6322 break;
6323 }
6324 case command_FieldId_list: {
6325 retval = bool_ReadStrptrMaybe(parent.list, strval);
6326 break;
6327 }
6328 case command_FieldId_t: {
6329 retval = bool_ReadStrptrMaybe(parent.t, strval);
6330 break;
6331 }
6332 case command_FieldId_data_dir: {
6333 retval = algo::cstring_ReadStrptrMaybe(parent.data_dir, strval);
6334 break;
6335 }
6336 case command_FieldId_schema: {
6337 retval = algo::cstring_ReadStrptrMaybe(parent.schema, strval);
6338 break;
6339 }
6340 case command_FieldId_related: {
6341 retval = algo::cstring_ReadStrptrMaybe(parent.related, strval);
6342 break;
6343 }
6344 case command_FieldId_notssimfile: {
6345 retval = notssimfile_ReadStrptrMaybe(parent, strval);
6346 break;
6347 }
6348 case command_FieldId_checkable: {
6349 retval = bool_ReadStrptrMaybe(parent.checkable, strval);
6350 break;
6351 }
6352 case command_FieldId_r: {
6353 retval = r_ReadStrptrMaybe(parent, strval);
6354 break;
6355 }
6356 default: break;
6357 }
6358 if (!retval) {
6359 algo_lib::AppendErrtext("attr",field);
6360 }
6361 return retval;
6362}
6363
6364// --- command.acr_in..ReadTupleMaybe
6365// Read fields of command::acr_in from attributes of ascii tuple TUPLE
6366bool command::acr_in_ReadTupleMaybe(command::acr_in &parent, algo::Tuple &tuple) {
6367 bool retval = true;
6368 int anon_idx = 0;
6369 ind_beg(algo::Tuple_attrs_curs,attr,tuple) {
6370 if (ch_N(attr.name) == 0) {
6371 attr.name = acr_in_GetAnon(parent, anon_idx++);
6372 }
6373 retval = acr_in_ReadFieldMaybe(parent, attr.name, attr.value);
6374 if (!retval) {
6375 break;
6376 }
6377 }ind_end;
6378 return retval;
6379}
6380
6381// --- command.acr_in..Init
6382// Set all fields to initial values.
6383void command::acr_in_Init(command::acr_in& parent) {
6384 Regx_ReadSql(parent.ns, "", true);
6385 parent.data = bool(false);
6386 parent.sigcheck = bool(true);
6387 parent.list = bool(false);
6388 parent.t = bool(false);
6389 parent.data_dir = algo::strptr("data");
6390 parent.schema = algo::strptr("data");
6391 parent.related = algo::strptr("");
6392 Regx_ReadSql(parent.notssimfile, "", true);
6393 parent.checkable = bool(false);
6394 Regx_ReadSql(parent.r, "", true);
6395}
6396
6397// --- command.acr_in..ToCmdline
6398// Convenience function that returns a full command line
6399// Assume command is in a directory called bin
6400tempstr command::acr_in_ToCmdline(command::acr_in& row) {
6401 tempstr ret;
6402 ret << "bin/acr_in ";
6403 acr_in_PrintArgv(row, ret);
6404 // inherit less intense verbose, debug options
6405 for (int i = 1; i < algo_lib::_db.cmdline.verbose; i++) {
6406 ret << " -verbose";
6407 }
6408 for (int i = 1; i < algo_lib::_db.cmdline.debug; i++) {
6409 ret << " -debug";
6410 }
6411 return ret;
6412}
6413
6414// --- command.acr_in..PrintArgv
6415// print string representation of ROW to string STR
6416// cfmt:command.acr_in.Argv printfmt:Auto
6417void command::acr_in_PrintArgv(command::acr_in& row, algo::cstring& str) {
6418 algo::tempstr temp;
6419 (void)temp;
6420 (void)str;
6421 ch_RemoveAll(temp);
6422 command::ns_Print(const_cast<command::acr_in&>(row), temp);
6423 str << " -ns:";
6424 strptr_PrintBash(temp,str);
6425 if (!(row.data == false)) {
6426 ch_RemoveAll(temp);
6427 bool_Print(row.data, temp);
6428 str << " -data:";
6429 strptr_PrintBash(temp,str);
6430 }
6431 if (!(row.sigcheck == true)) {
6432 ch_RemoveAll(temp);
6433 bool_Print(row.sigcheck, temp);
6434 str << " -sigcheck:";
6435 strptr_PrintBash(temp,str);
6436 }
6437 if (!(row.list == false)) {
6438 ch_RemoveAll(temp);
6439 bool_Print(row.list, temp);
6440 str << " -list:";
6441 strptr_PrintBash(temp,str);
6442 }
6443 if (!(row.t == false)) {
6444 ch_RemoveAll(temp);
6445 bool_Print(row.t, temp);
6446 str << " -t:";
6447 strptr_PrintBash(temp,str);
6448 }
6449 if (!(row.data_dir == "data")) {
6450 ch_RemoveAll(temp);
6451 cstring_Print(row.data_dir, temp);
6452 str << " -data_dir:";
6453 strptr_PrintBash(temp,str);
6454 }
6455 if (!(row.schema == "data")) {
6456 ch_RemoveAll(temp);
6457 cstring_Print(row.schema, temp);
6458 str << " -schema:";
6459 strptr_PrintBash(temp,str);
6460 }
6461 if (!(row.related == "")) {
6462 ch_RemoveAll(temp);
6463 cstring_Print(row.related, temp);
6464 str << " -related:";
6465 strptr_PrintBash(temp,str);
6466 }
6467 if (!(row.notssimfile.expr == "")) {
6468 ch_RemoveAll(temp);
6469 command::notssimfile_Print(const_cast<command::acr_in&>(row), temp);
6470 str << " -notssimfile:";
6471 strptr_PrintBash(temp,str);
6472 }
6473 if (!(row.checkable == false)) {
6474 ch_RemoveAll(temp);
6475 bool_Print(row.checkable, temp);
6476 str << " -checkable:";
6477 strptr_PrintBash(temp,str);
6478 }
6479 if (!(row.r.expr == "")) {
6480 ch_RemoveAll(temp);
6481 command::r_Print(const_cast<command::acr_in&>(row), temp);
6482 str << " -r:";
6483 strptr_PrintBash(temp,str);
6484 }
6485}
6486
6487// --- command.acr_in..GetAnon
6488algo::strptr command::acr_in_GetAnon(command::acr_in &parent, i32 idx) {
6489 (void)parent;//only to avoid -Wunused-parameter
6490 switch(idx) {
6491 case(0): return strptr("ns", 2);
6492 default: return algo::strptr();
6493 }
6494}
6495
6496// --- command.acr_in..NArgs
6497// Used with command lines
6498// Return # of command-line arguments that must follow this argument
6499// If FIELD is invalid, return -1
6500i32 command::acr_in_NArgs(command::FieldId field, algo::strptr& out_dflt, bool* out_anon) {
6501 i32 retval = 1;
6502 switch (field) {
6503 case command_FieldId_ns: { // $comment
6504 *out_anon = true;
6505 } break;
6506 case command_FieldId_data: { // $comment
6507 *out_anon = false;
6508 retval=0;
6509 out_dflt="Y";
6510 } break;
6511 case command_FieldId_sigcheck: { // bool: no argument required but value may be specified as data:Y
6512 *out_anon = false;
6513 retval=0;
6514 out_dflt="Y";
6515 } break;
6516 case command_FieldId_list: { // bool: no argument required but value may be specified as sigcheck:Y
6517 *out_anon = false;
6518 retval=0;
6519 out_dflt="Y";
6520 } break;
6521 case command_FieldId_t: { // bool: no argument required but value may be specified as list:Y
6522 *out_anon = false;
6523 retval=0;
6524 out_dflt="Y";
6525 } break;
6526 case command_FieldId_data_dir: { // bool: no argument required but value may be specified as t:Y
6527 *out_anon = false;
6528 } break;
6529 case command_FieldId_schema: { // bool: no argument required but value may be specified as t:Y
6530 *out_anon = false;
6531 } break;
6532 case command_FieldId_related: { // bool: no argument required but value may be specified as t:Y
6533 *out_anon = false;
6534 } break;
6535 case command_FieldId_notssimfile: { // bool: no argument required but value may be specified as t:Y
6536 *out_anon = false;
6537 } break;
6538 case command_FieldId_checkable: { // bool: no argument required but value may be specified as t:Y
6539 *out_anon = false;
6540 retval=0;
6541 out_dflt="Y";
6542 } break;
6543 case command_FieldId_r: { // bool: no argument required but value may be specified as checkable:Y
6544 *out_anon = false;
6545 } break;
6546 default:
6547 retval=-1; // unrecognized
6548 }
6549 return retval;
6550}
6551
6552// --- command.acr_in_proc.acr_in.Start
6553// Start subprocess
6554// If subprocess already running, do nothing. Otherwise, start it
6555int command::acr_in_Start(command::acr_in_proc& parent) {
6556 int retval = 0;
6557 if (parent.pid == 0) {
6558 verblog(acr_in_ToCmdline(parent)); // maybe print command
6559#ifdef WIN32
6560 algo_lib::ResolveExecFname(parent.path);
6561 tempstr cmdline(acr_in_ToCmdline(parent));
6562 parent.pid = dospawn(Zeroterm(parent.path),Zeroterm(cmdline),parent.timeout,parent.fstdin,parent.fstdout,parent.fstderr);
6563#else
6564 parent.pid = fork();
6565 if (parent.pid == 0) { // child
6566 algo_lib::DieWithParent();
6567 if (parent.timeout > 0) {
6568 alarm(parent.timeout);
6569 }
6570 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstdin , 0);
6571 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstdout, 1);
6572 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstderr, 2);
6573 if (retval==0) retval= acr_in_Execv(parent);
6574 if (retval != 0) { // if start fails, print error
6575 int err=errno;
6576 prerr("command.acr_in_execv"
6577 <<Keyval("errno",err)
6578 <<Keyval("errstr",strerror(err))
6579 <<Keyval("comment","Execv failed"));
6580 }
6581 _exit(127); // if failed to start, exit anyway
6582 } else if (parent.pid == -1) {
6583 retval = errno; // failed to fork
6584 }
6585#endif
6586 }
6587 parent.status = parent.pid > 0 ? 0 : -1; // if didn't start, set error status
6588 return retval;
6589}
6590
6591// --- command.acr_in_proc.acr_in.StartRead
6592// Start subprocess & Read output
6593algo::Fildes command::acr_in_StartRead(command::acr_in_proc& parent, algo_lib::FFildes &read) {
6594 int pipefd[2];
6595 int rc=pipe(pipefd);
6596 (void)rc;
6597 read.fd.value = pipefd[0];
6598 parent.fstdout << ">&" << pipefd[1];
6599 acr_in_Start(parent);
6600 (void)close(pipefd[1]);
6601 return read.fd;
6602}
6603
6604// --- command.acr_in_proc.acr_in.Kill
6605// Kill subprocess and wait
6606void command::acr_in_Kill(command::acr_in_proc& parent) {
6607 if (parent.pid != 0) {
6608 kill(parent.pid,9);
6609 acr_in_Wait(parent);
6610 }
6611}
6612
6613// --- command.acr_in_proc.acr_in.Wait
6614// Wait for subprocess to return
6615void command::acr_in_Wait(command::acr_in_proc& parent) {
6616 if (parent.pid > 0) {
6617 int wait_flags = 0;
6618 int wait_status = 0;
6619 int rc = -1;
6620 do {
6621 // really wait for subprocess to exit
6622 rc = waitpid(parent.pid,&wait_status,wait_flags);
6623 } while (rc==-1 && errno==EINTR);
6624 if (rc == parent.pid) {
6625 parent.status = wait_status;
6626 parent.pid = 0;
6627 }
6628 }
6629}
6630
6631// --- command.acr_in_proc.acr_in.Exec
6632// Start + Wait
6633// Execute subprocess and return exit code
6634int command::acr_in_Exec(command::acr_in_proc& parent) {
6635 acr_in_Start(parent);
6636 acr_in_Wait(parent);
6637 return parent.status;
6638}
6639
6640// --- command.acr_in_proc.acr_in.ExecX
6641// Start + Wait, throw exception on error
6642// Execute subprocess; throw human-readable exception on error
6643void command::acr_in_ExecX(command::acr_in_proc& parent) {
6644 int rc = acr_in_Exec(parent);
6645 vrfy(rc==0, tempstr() << "algo_lib.exec" << Keyval("cmd",acr_in_ToCmdline(parent))
6646 << Keyval("comment",algo::DescribeWaitStatus(parent.status)));
6647}
6648
6649// --- command.acr_in_proc.acr_in.Execv
6650// Call execv()
6651// Call execv with specified parameters
6652int command::acr_in_Execv(command::acr_in_proc& parent) {
6653 int ret = 0;
6654 algo::StringAry args;
6655 acr_in_ToArgv(parent, args);
6656 char **argv = (char**)alloca((ary_N(args)+1)*sizeof(*argv));
6657 ind_beg(algo::StringAry_ary_curs,arg,args) {
6658 argv[ind_curs(arg).index] = Zeroterm(arg);
6659 }ind_end;
6660 argv[ary_N(args)] = NULL;
6661 // if parent.path is relative, search for it in PATH
6662 algo_lib::ResolveExecFname(parent.path);
6663 ret = execv(Zeroterm(parent.path),argv);
6664 return ret;
6665}
6666
6667// --- command.acr_in_proc.acr_in.ToCmdline
6668algo::tempstr command::acr_in_ToCmdline(command::acr_in_proc& parent) {
6669 algo::tempstr retval;
6670 retval << parent.path << " ";
6671 command::acr_in_PrintArgv(parent.cmd,retval);
6672 if (ch_N(parent.fstdin)) {
6673 retval << " " << parent.fstdin;
6674 }
6675 if (ch_N(parent.fstdout)) {
6676 retval << " " << parent.fstdout;
6677 }
6678 if (ch_N(parent.fstderr)) {
6679 retval << " 2" << parent.fstderr;
6680 }
6681 return retval;
6682}
6683
6684// --- command.acr_in_proc.acr_in.ToArgv
6685// Form array from the command line
6686void command::acr_in_ToArgv(command::acr_in_proc& parent, algo::StringAry& args) {
6687 ary_RemoveAll(args);
6688 ary_Alloc(args) << parent.path;
6689
6690 if (parent.cmd.ns.expr != "") {
6691 cstring *arg = &ary_Alloc(args);
6692 *arg << "-ns:";
6693 command::ns_Print(parent.cmd, *arg);
6694 }
6695
6696 if (parent.cmd.data != false) {
6697 cstring *arg = &ary_Alloc(args);
6698 *arg << "-data:";
6699 bool_Print(parent.cmd.data, *arg);
6700 }
6701
6702 if (parent.cmd.sigcheck != true) {
6703 cstring *arg = &ary_Alloc(args);
6704 *arg << "-sigcheck:";
6705 bool_Print(parent.cmd.sigcheck, *arg);
6706 }
6707
6708 if (parent.cmd.list != false) {
6709 cstring *arg = &ary_Alloc(args);
6710 *arg << "-list:";
6711 bool_Print(parent.cmd.list, *arg);
6712 }
6713
6714 if (parent.cmd.t != false) {
6715 cstring *arg = &ary_Alloc(args);
6716 *arg << "-t:";
6717 bool_Print(parent.cmd.t, *arg);
6718 }
6719
6720 if (parent.cmd.data_dir != "data") {
6721 cstring *arg = &ary_Alloc(args);
6722 *arg << "-data_dir:";
6723 cstring_Print(parent.cmd.data_dir, *arg);
6724 }
6725
6726 if (parent.cmd.schema != "data") {
6727 cstring *arg = &ary_Alloc(args);
6728 *arg << "-schema:";
6729 cstring_Print(parent.cmd.schema, *arg);
6730 }
6731
6732 if (parent.cmd.related != "") {
6733 cstring *arg = &ary_Alloc(args);
6734 *arg << "-related:";
6735 cstring_Print(parent.cmd.related, *arg);
6736 }
6737
6738 if (parent.cmd.notssimfile.expr != "") {
6739 cstring *arg = &ary_Alloc(args);
6740 *arg << "-notssimfile:";
6741 command::notssimfile_Print(parent.cmd, *arg);
6742 }
6743
6744 if (parent.cmd.checkable != false) {
6745 cstring *arg = &ary_Alloc(args);
6746 *arg << "-checkable:";
6747 bool_Print(parent.cmd.checkable, *arg);
6748 }
6749
6750 if (parent.cmd.r.expr != "") {
6751 cstring *arg = &ary_Alloc(args);
6752 *arg << "-r:";
6753 command::r_Print(parent.cmd, *arg);
6754 }
6755 for (int i=1; i < algo_lib::_db.cmdline.verbose; ++i) {
6756 ary_Alloc(args) << "-verbose";
6757 }
6758}
6759
6760// --- command.acr_in_proc..Uninit
6761void command::acr_in_proc_Uninit(command::acr_in_proc& parent) {
6762 command::acr_in_proc &row = parent; (void)row;
6763
6764 // command.acr_in_proc.acr_in.Uninit (Exec) //
6765 acr_in_Kill(parent); // kill child, ensure forward progress
6766}
6767
6768// --- command.acr_my.nsdb.Print
6769// Print back to string
6770void command::nsdb_Print(command::acr_my& parent, algo::cstring &out) {
6771 Regx_Print(parent.nsdb, out);
6772}
6773
6774// --- command.acr_my.nsdb.ReadStrptrMaybe
6775// Read Regx from string
6776// Convert string to field. Return success value
6777bool command::nsdb_ReadStrptrMaybe(command::acr_my& parent, algo::strptr in) {
6778 bool retval = true;
6779 Regx_ReadSql(parent.nsdb, in, true);
6780 return retval;
6781}
6782
6783// --- command.acr_my..ReadFieldMaybe
6784bool command::acr_my_ReadFieldMaybe(command::acr_my& parent, algo::strptr field, algo::strptr strval) {
6785 bool retval = true;
6786 command::FieldId field_id;
6787 (void)value_SetStrptrMaybe(field_id,field);
6788 switch(field_id) {
6789 case command_FieldId_nsdb: {
6790 retval = nsdb_ReadStrptrMaybe(parent, strval);
6791 break;
6792 }
6793 case command_FieldId_in: {
6794 retval = algo::cstring_ReadStrptrMaybe(parent.in, strval);
6795 break;
6796 }
6797 case command_FieldId_schema: {
6798 retval = algo::cstring_ReadStrptrMaybe(parent.schema, strval);
6799 break;
6800 }
6801 case command_FieldId_fldfunc: {
6802 retval = bool_ReadStrptrMaybe(parent.fldfunc, strval);
6803 break;
6804 }
6805 case command_FieldId_fkey: {
6806 retval = bool_ReadStrptrMaybe(parent.fkey, strval);
6807 break;
6808 }
6809 case command_FieldId_e: {
6810 retval = bool_ReadStrptrMaybe(parent.e, strval);
6811 break;
6812 }
6813 case command_FieldId_start: {
6814 retval = bool_ReadStrptrMaybe(parent.start, strval);
6815 break;
6816 }
6817 case command_FieldId_stop: {
6818 retval = bool_ReadStrptrMaybe(parent.stop, strval);
6819 break;
6820 }
6821 case command_FieldId_abort: {
6822 retval = bool_ReadStrptrMaybe(parent.abort, strval);
6823 break;
6824 }
6825 case command_FieldId_shell: {
6826 retval = bool_ReadStrptrMaybe(parent.shell, strval);
6827 break;
6828 }
6829 case command_FieldId_serv: {
6830 retval = bool_ReadStrptrMaybe(parent.serv, strval);
6831 break;
6832 }
6833 default: break;
6834 }
6835 if (!retval) {
6836 algo_lib::AppendErrtext("attr",field);
6837 }
6838 return retval;
6839}
6840
6841// --- command.acr_my..ReadTupleMaybe
6842// Read fields of command::acr_my from attributes of ascii tuple TUPLE
6843bool command::acr_my_ReadTupleMaybe(command::acr_my &parent, algo::Tuple &tuple) {
6844 bool retval = true;
6845 int anon_idx = 0;
6846 ind_beg(algo::Tuple_attrs_curs,attr,tuple) {
6847 if (ch_N(attr.name) == 0) {
6848 attr.name = acr_my_GetAnon(parent, anon_idx++);
6849 }
6850 retval = acr_my_ReadFieldMaybe(parent, attr.name, attr.value);
6851 if (!retval) {
6852 break;
6853 }
6854 }ind_end;
6855 return retval;
6856}
6857
6858// --- command.acr_my..Init
6859// Set all fields to initial values.
6860void command::acr_my_Init(command::acr_my& parent) {
6861 Regx_ReadSql(parent.nsdb, "", true);
6862 parent.in = algo::strptr("data");
6863 parent.schema = algo::strptr("data");
6864 parent.fldfunc = bool(false);
6865 parent.fkey = bool(false);
6866 parent.e = bool(false);
6867 parent.start = bool(false);
6868 parent.stop = bool(false);
6869 parent.abort = bool(false);
6870 parent.shell = bool(false);
6871 parent.serv = bool(false);
6872}
6873
6874// --- command.acr_my..ToCmdline
6875// Convenience function that returns a full command line
6876// Assume command is in a directory called bin
6877tempstr command::acr_my_ToCmdline(command::acr_my& row) {
6878 tempstr ret;
6879 ret << "bin/acr_my ";
6880 acr_my_PrintArgv(row, ret);
6881 // inherit less intense verbose, debug options
6882 for (int i = 1; i < algo_lib::_db.cmdline.verbose; i++) {
6883 ret << " -verbose";
6884 }
6885 for (int i = 1; i < algo_lib::_db.cmdline.debug; i++) {
6886 ret << " -debug";
6887 }
6888 return ret;
6889}
6890
6891// --- command.acr_my..PrintArgv
6892// print string representation of ROW to string STR
6893// cfmt:command.acr_my.Argv printfmt:Tuple
6894void command::acr_my_PrintArgv(command::acr_my& row, algo::cstring& str) {
6895 algo::tempstr temp;
6896 (void)temp;
6897 (void)str;
6898 ch_RemoveAll(temp);
6899 command::nsdb_Print(const_cast<command::acr_my&>(row), temp);
6900 str << " -nsdb:";
6901 strptr_PrintBash(temp,str);
6902 if (!(row.in == "data")) {
6903 ch_RemoveAll(temp);
6904 cstring_Print(row.in, temp);
6905 str << " -in:";
6906 strptr_PrintBash(temp,str);
6907 }
6908 if (!(row.schema == "data")) {
6909 ch_RemoveAll(temp);
6910 cstring_Print(row.schema, temp);
6911 str << " -schema:";
6912 strptr_PrintBash(temp,str);
6913 }
6914 if (!(row.fldfunc == false)) {
6915 ch_RemoveAll(temp);
6916 bool_Print(row.fldfunc, temp);
6917 str << " -fldfunc:";
6918 strptr_PrintBash(temp,str);
6919 }
6920 if (!(row.fkey == false)) {
6921 ch_RemoveAll(temp);
6922 bool_Print(row.fkey, temp);
6923 str << " -fkey:";
6924 strptr_PrintBash(temp,str);
6925 }
6926 if (!(row.e == false)) {
6927 ch_RemoveAll(temp);
6928 bool_Print(row.e, temp);
6929 str << " -e:";
6930 strptr_PrintBash(temp,str);
6931 }
6932 if (!(row.start == false)) {
6933 ch_RemoveAll(temp);
6934 bool_Print(row.start, temp);
6935 str << " -start:";
6936 strptr_PrintBash(temp,str);
6937 }
6938 if (!(row.stop == false)) {
6939 ch_RemoveAll(temp);
6940 bool_Print(row.stop, temp);
6941 str << " -stop:";
6942 strptr_PrintBash(temp,str);
6943 }
6944 if (!(row.abort == false)) {
6945 ch_RemoveAll(temp);
6946 bool_Print(row.abort, temp);
6947 str << " -abort:";
6948 strptr_PrintBash(temp,str);
6949 }
6950 if (!(row.shell == false)) {
6951 ch_RemoveAll(temp);
6952 bool_Print(row.shell, temp);
6953 str << " -shell:";
6954 strptr_PrintBash(temp,str);
6955 }
6956 if (!(row.serv == false)) {
6957 ch_RemoveAll(temp);
6958 bool_Print(row.serv, temp);
6959 str << " -serv:";
6960 strptr_PrintBash(temp,str);
6961 }
6962}
6963
6964// --- command.acr_my..GetAnon
6965algo::strptr command::acr_my_GetAnon(command::acr_my &parent, i32 idx) {
6966 (void)parent;//only to avoid -Wunused-parameter
6967 switch(idx) {
6968 case(0): return strptr("nsdb", 4);
6969 default: return algo::strptr();
6970 }
6971}
6972
6973// --- command.acr_my..NArgs
6974// Used with command lines
6975// Return # of command-line arguments that must follow this argument
6976// If FIELD is invalid, return -1
6977i32 command::acr_my_NArgs(command::FieldId field, algo::strptr& out_dflt, bool* out_anon) {
6978 i32 retval = 1;
6979 switch (field) {
6980 case command_FieldId_nsdb: { // $comment
6981 *out_anon = true;
6982 } break;
6983 case command_FieldId_in: { // $comment
6984 *out_anon = false;
6985 } break;
6986 case command_FieldId_schema: { // $comment
6987 *out_anon = false;
6988 } break;
6989 case command_FieldId_fldfunc: { // $comment
6990 *out_anon = false;
6991 retval=0;
6992 out_dflt="Y";
6993 } break;
6994 case command_FieldId_fkey: { // bool: no argument required but value may be specified as fldfunc:Y
6995 *out_anon = false;
6996 retval=0;
6997 out_dflt="Y";
6998 } break;
6999 case command_FieldId_e: { // bool: no argument required but value may be specified as fkey:Y
7000 *out_anon = false;
7001 retval=0;
7002 out_dflt="Y";
7003 } break;
7004 case command_FieldId_start: { // bool: no argument required but value may be specified as e:Y
7005 *out_anon = false;
7006 retval=0;
7007 out_dflt="Y";
7008 } break;
7009 case command_FieldId_stop: { // bool: no argument required but value may be specified as start:Y
7010 *out_anon = false;
7011 retval=0;
7012 out_dflt="Y";
7013 } break;
7014 case command_FieldId_abort: { // bool: no argument required but value may be specified as stop:Y
7015 *out_anon = false;
7016 retval=0;
7017 out_dflt="Y";
7018 } break;
7019 case command_FieldId_shell: { // bool: no argument required but value may be specified as abort:Y
7020 *out_anon = false;
7021 retval=0;
7022 out_dflt="Y";
7023 } break;
7024 case command_FieldId_serv: { // bool: no argument required but value may be specified as shell:Y
7025 *out_anon = false;
7026 retval=0;
7027 out_dflt="Y";
7028 } break;
7029 default:
7030 retval=-1; // unrecognized
7031 }
7032 return retval;
7033}
7034
7035// --- command.acr_my_proc.acr_my.Start
7036// Start subprocess
7037// If subprocess already running, do nothing. Otherwise, start it
7038int command::acr_my_Start(command::acr_my_proc& parent) {
7039 int retval = 0;
7040 if (parent.pid == 0) {
7041 verblog(acr_my_ToCmdline(parent)); // maybe print command
7042#ifdef WIN32
7043 algo_lib::ResolveExecFname(parent.path);
7044 tempstr cmdline(acr_my_ToCmdline(parent));
7045 parent.pid = dospawn(Zeroterm(parent.path),Zeroterm(cmdline),parent.timeout,parent.fstdin,parent.fstdout,parent.fstderr);
7046#else
7047 parent.pid = fork();
7048 if (parent.pid == 0) { // child
7049 algo_lib::DieWithParent();
7050 if (parent.timeout > 0) {
7051 alarm(parent.timeout);
7052 }
7053 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstdin , 0);
7054 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstdout, 1);
7055 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstderr, 2);
7056 if (retval==0) retval= acr_my_Execv(parent);
7057 if (retval != 0) { // if start fails, print error
7058 int err=errno;
7059 prerr("command.acr_my_execv"
7060 <<Keyval("errno",err)
7061 <<Keyval("errstr",strerror(err))
7062 <<Keyval("comment","Execv failed"));
7063 }
7064 _exit(127); // if failed to start, exit anyway
7065 } else if (parent.pid == -1) {
7066 retval = errno; // failed to fork
7067 }
7068#endif
7069 }
7070 parent.status = parent.pid > 0 ? 0 : -1; // if didn't start, set error status
7071 return retval;
7072}
7073
7074// --- command.acr_my_proc.acr_my.StartRead
7075// Start subprocess & Read output
7076algo::Fildes command::acr_my_StartRead(command::acr_my_proc& parent, algo_lib::FFildes &read) {
7077 int pipefd[2];
7078 int rc=pipe(pipefd);
7079 (void)rc;
7080 read.fd.value = pipefd[0];
7081 parent.fstdout << ">&" << pipefd[1];
7082 acr_my_Start(parent);
7083 (void)close(pipefd[1]);
7084 return read.fd;
7085}
7086
7087// --- command.acr_my_proc.acr_my.Kill
7088// Kill subprocess and wait
7089void command::acr_my_Kill(command::acr_my_proc& parent) {
7090 if (parent.pid != 0) {
7091 kill(parent.pid,9);
7092 acr_my_Wait(parent);
7093 }
7094}
7095
7096// --- command.acr_my_proc.acr_my.Wait
7097// Wait for subprocess to return
7098void command::acr_my_Wait(command::acr_my_proc& parent) {
7099 if (parent.pid > 0) {
7100 int wait_flags = 0;
7101 int wait_status = 0;
7102 int rc = -1;
7103 do {
7104 // really wait for subprocess to exit
7105 rc = waitpid(parent.pid,&wait_status,wait_flags);
7106 } while (rc==-1 && errno==EINTR);
7107 if (rc == parent.pid) {
7108 parent.status = wait_status;
7109 parent.pid = 0;
7110 }
7111 }
7112}
7113
7114// --- command.acr_my_proc.acr_my.Exec
7115// Start + Wait
7116// Execute subprocess and return exit code
7117int command::acr_my_Exec(command::acr_my_proc& parent) {
7118 acr_my_Start(parent);
7119 acr_my_Wait(parent);
7120 return parent.status;
7121}
7122
7123// --- command.acr_my_proc.acr_my.ExecX
7124// Start + Wait, throw exception on error
7125// Execute subprocess; throw human-readable exception on error
7126void command::acr_my_ExecX(command::acr_my_proc& parent) {
7127 int rc = acr_my_Exec(parent);
7128 vrfy(rc==0, tempstr() << "algo_lib.exec" << Keyval("cmd",acr_my_ToCmdline(parent))
7129 << Keyval("comment",algo::DescribeWaitStatus(parent.status)));
7130}
7131
7132// --- command.acr_my_proc.acr_my.Execv
7133// Call execv()
7134// Call execv with specified parameters
7135int command::acr_my_Execv(command::acr_my_proc& parent) {
7136 int ret = 0;
7137 algo::StringAry args;
7138 acr_my_ToArgv(parent, args);
7139 char **argv = (char**)alloca((ary_N(args)+1)*sizeof(*argv));
7140 ind_beg(algo::StringAry_ary_curs,arg,args) {
7141 argv[ind_curs(arg).index] = Zeroterm(arg);
7142 }ind_end;
7143 argv[ary_N(args)] = NULL;
7144 // if parent.path is relative, search for it in PATH
7145 algo_lib::ResolveExecFname(parent.path);
7146 ret = execv(Zeroterm(parent.path),argv);
7147 return ret;
7148}
7149
7150// --- command.acr_my_proc.acr_my.ToCmdline
7151algo::tempstr command::acr_my_ToCmdline(command::acr_my_proc& parent) {
7152 algo::tempstr retval;
7153 retval << parent.path << " ";
7154 command::acr_my_PrintArgv(parent.cmd,retval);
7155 if (ch_N(parent.fstdin)) {
7156 retval << " " << parent.fstdin;
7157 }
7158 if (ch_N(parent.fstdout)) {
7159 retval << " " << parent.fstdout;
7160 }
7161 if (ch_N(parent.fstderr)) {
7162 retval << " 2" << parent.fstderr;
7163 }
7164 return retval;
7165}
7166
7167// --- command.acr_my_proc.acr_my.ToArgv
7168// Form array from the command line
7169void command::acr_my_ToArgv(command::acr_my_proc& parent, algo::StringAry& args) {
7170 ary_RemoveAll(args);
7171 ary_Alloc(args) << parent.path;
7172
7173 if (parent.cmd.nsdb.expr != "") {
7174 cstring *arg = &ary_Alloc(args);
7175 *arg << "-nsdb:";
7176 command::nsdb_Print(parent.cmd, *arg);
7177 }
7178
7179 if (parent.cmd.in != "data") {
7180 cstring *arg = &ary_Alloc(args);
7181 *arg << "-in:";
7182 cstring_Print(parent.cmd.in, *arg);
7183 }
7184
7185 if (parent.cmd.schema != "data") {
7186 cstring *arg = &ary_Alloc(args);
7187 *arg << "-schema:";
7188 cstring_Print(parent.cmd.schema, *arg);
7189 }
7190
7191 if (parent.cmd.fldfunc != false) {
7192 cstring *arg = &ary_Alloc(args);
7193 *arg << "-fldfunc:";
7194 bool_Print(parent.cmd.fldfunc, *arg);
7195 }
7196
7197 if (parent.cmd.fkey != false) {
7198 cstring *arg = &ary_Alloc(args);
7199 *arg << "-fkey:";
7200 bool_Print(parent.cmd.fkey, *arg);
7201 }
7202
7203 if (parent.cmd.e != false) {
7204 cstring *arg = &ary_Alloc(args);
7205 *arg << "-e:";
7206 bool_Print(parent.cmd.e, *arg);
7207 }
7208
7209 if (parent.cmd.start != false) {
7210 cstring *arg = &ary_Alloc(args);
7211 *arg << "-start:";
7212 bool_Print(parent.cmd.start, *arg);
7213 }
7214
7215 if (parent.cmd.stop != false) {
7216 cstring *arg = &ary_Alloc(args);
7217 *arg << "-stop:";
7218 bool_Print(parent.cmd.stop, *arg);
7219 }
7220
7221 if (parent.cmd.abort != false) {
7222 cstring *arg = &ary_Alloc(args);
7223 *arg << "-abort:";
7224 bool_Print(parent.cmd.abort, *arg);
7225 }
7226
7227 if (parent.cmd.shell != false) {
7228 cstring *arg = &ary_Alloc(args);
7229 *arg << "-shell:";
7230 bool_Print(parent.cmd.shell, *arg);
7231 }
7232
7233 if (parent.cmd.serv != false) {
7234 cstring *arg = &ary_Alloc(args);
7235 *arg << "-serv:";
7236 bool_Print(parent.cmd.serv, *arg);
7237 }
7238 for (int i=1; i < algo_lib::_db.cmdline.verbose; ++i) {
7239 ary_Alloc(args) << "-verbose";
7240 }
7241}
7242
7243// --- command.acr_my_proc..Uninit
7244void command::acr_my_proc_Uninit(command::acr_my_proc& parent) {
7245 command::acr_my_proc &row = parent; (void)row;
7246
7247 // command.acr_my_proc.acr_my.Uninit (Exec) //
7248 acr_my_Kill(parent); // kill child, ensure forward progress
7249}
7250
7251// --- command.acr_proc.acr.Start
7252// Start subprocess
7253// If subprocess already running, do nothing. Otherwise, start it
7254int command::acr_Start(command::acr_proc& parent) {
7255 int retval = 0;
7256 if (parent.pid == 0) {
7257 verblog(acr_ToCmdline(parent)); // maybe print command
7258#ifdef WIN32
7259 algo_lib::ResolveExecFname(parent.path);
7260 tempstr cmdline(acr_ToCmdline(parent));
7261 parent.pid = dospawn(Zeroterm(parent.path),Zeroterm(cmdline),parent.timeout,parent.fstdin,parent.fstdout,parent.fstderr);
7262#else
7263 parent.pid = fork();
7264 if (parent.pid == 0) { // child
7265 algo_lib::DieWithParent();
7266 if (parent.timeout > 0) {
7267 alarm(parent.timeout);
7268 }
7269 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstdin , 0);
7270 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstdout, 1);
7271 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstderr, 2);
7272 if (retval==0) retval= acr_Execv(parent);
7273 if (retval != 0) { // if start fails, print error
7274 int err=errno;
7275 prerr("command.acr_execv"
7276 <<Keyval("errno",err)
7277 <<Keyval("errstr",strerror(err))
7278 <<Keyval("comment","Execv failed"));
7279 }
7280 _exit(127); // if failed to start, exit anyway
7281 } else if (parent.pid == -1) {
7282 retval = errno; // failed to fork
7283 }
7284#endif
7285 }
7286 parent.status = parent.pid > 0 ? 0 : -1; // if didn't start, set error status
7287 return retval;
7288}
7289
7290// --- command.acr_proc.acr.StartRead
7291// Start subprocess & Read output
7292algo::Fildes command::acr_StartRead(command::acr_proc& parent, algo_lib::FFildes &read) {
7293 int pipefd[2];
7294 int rc=pipe(pipefd);
7295 (void)rc;
7296 read.fd.value = pipefd[0];
7297 parent.fstdout << ">&" << pipefd[1];
7298 acr_Start(parent);
7299 (void)close(pipefd[1]);
7300 return read.fd;
7301}
7302
7303// --- command.acr_proc.acr.Kill
7304// Kill subprocess and wait
7305void command::acr_Kill(command::acr_proc& parent) {
7306 if (parent.pid != 0) {
7307 kill(parent.pid,9);
7308 acr_Wait(parent);
7309 }
7310}
7311
7312// --- command.acr_proc.acr.Wait
7313// Wait for subprocess to return
7314void command::acr_Wait(command::acr_proc& parent) {
7315 if (parent.pid > 0) {
7316 int wait_flags = 0;
7317 int wait_status = 0;
7318 int rc = -1;
7319 do {
7320 // really wait for subprocess to exit
7321 rc = waitpid(parent.pid,&wait_status,wait_flags);
7322 } while (rc==-1 && errno==EINTR);
7323 if (rc == parent.pid) {
7324 parent.status = wait_status;
7325 parent.pid = 0;
7326 }
7327 }
7328}
7329
7330// --- command.acr_proc.acr.Exec
7331// Start + Wait
7332// Execute subprocess and return exit code
7333int command::acr_Exec(command::acr_proc& parent) {
7334 acr_Start(parent);
7335 acr_Wait(parent);
7336 return parent.status;
7337}
7338
7339// --- command.acr_proc.acr.ExecX
7340// Start + Wait, throw exception on error
7341// Execute subprocess; throw human-readable exception on error
7342void command::acr_ExecX(command::acr_proc& parent) {
7343 int rc = acr_Exec(parent);
7344 vrfy(rc==0, tempstr() << "algo_lib.exec" << Keyval("cmd",acr_ToCmdline(parent))
7345 << Keyval("comment",algo::DescribeWaitStatus(parent.status)));
7346}
7347
7348// --- command.acr_proc.acr.Execv
7349// Call execv()
7350// Call execv with specified parameters
7351int command::acr_Execv(command::acr_proc& parent) {
7352 int ret = 0;
7353 algo::StringAry args;
7354 acr_ToArgv(parent, args);
7355 char **argv = (char**)alloca((ary_N(args)+1)*sizeof(*argv));
7356 ind_beg(algo::StringAry_ary_curs,arg,args) {
7357 argv[ind_curs(arg).index] = Zeroterm(arg);
7358 }ind_end;
7359 argv[ary_N(args)] = NULL;
7360 // if parent.path is relative, search for it in PATH
7361 algo_lib::ResolveExecFname(parent.path);
7362 ret = execv(Zeroterm(parent.path),argv);
7363 return ret;
7364}
7365
7366// --- command.acr_proc.acr.ToCmdline
7367algo::tempstr command::acr_ToCmdline(command::acr_proc& parent) {
7368 algo::tempstr retval;
7369 retval << parent.path << " ";
7370 command::acr_PrintArgv(parent.cmd,retval);
7371 if (ch_N(parent.fstdin)) {
7372 retval << " " << parent.fstdin;
7373 }
7374 if (ch_N(parent.fstdout)) {
7375 retval << " " << parent.fstdout;
7376 }
7377 if (ch_N(parent.fstderr)) {
7378 retval << " 2" << parent.fstderr;
7379 }
7380 return retval;
7381}
7382
7383// --- command.acr_proc.acr.ToArgv
7384// Form array from the command line
7385void command::acr_ToArgv(command::acr_proc& parent, algo::StringAry& args) {
7386 ary_RemoveAll(args);
7387 ary_Alloc(args) << parent.path;
7388
7389 if (parent.cmd.query != "") {
7390 cstring *arg = &ary_Alloc(args);
7391 *arg << "-query:";
7392 cstring_Print(parent.cmd.query, *arg);
7393 }
7394 ind_beg(command::acr_where_curs,value,parent.cmd) {
7395 cstring *arg = &ary_Alloc(args);
7396 *arg << "-where:";
7397 cstring_Print(value, *arg);
7398 }ind_end;
7399
7400 if (parent.cmd.in != "data") {
7401 cstring *arg = &ary_Alloc(args);
7402 *arg << "-in:";
7403 cstring_Print(parent.cmd.in, *arg);
7404 }
7405
7406 if (parent.cmd.del != false) {
7407 cstring *arg = &ary_Alloc(args);
7408 *arg << "-del:";
7409 bool_Print(parent.cmd.del, *arg);
7410 }
7411
7412 if (parent.cmd.sel != false) {
7413 cstring *arg = &ary_Alloc(args);
7414 *arg << "-sel:";
7415 bool_Print(parent.cmd.sel, *arg);
7416 }
7417
7418 if (parent.cmd.insert != false) {
7419 cstring *arg = &ary_Alloc(args);
7420 *arg << "-insert:";
7421 bool_Print(parent.cmd.insert, *arg);
7422 }
7423
7424 if (parent.cmd.replace != false) {
7425 cstring *arg = &ary_Alloc(args);
7426 *arg << "-replace:";
7427 bool_Print(parent.cmd.replace, *arg);
7428 }
7429
7430 if (parent.cmd.update != false) {
7431 cstring *arg = &ary_Alloc(args);
7432 *arg << "-update:";
7433 bool_Print(parent.cmd.update, *arg);
7434 }
7435
7436 if (parent.cmd.merge != false) {
7437 cstring *arg = &ary_Alloc(args);
7438 *arg << "-merge:";
7439 bool_Print(parent.cmd.merge, *arg);
7440 }
7441
7442 if (parent.cmd.unused != false) {
7443 cstring *arg = &ary_Alloc(args);
7444 *arg << "-unused:";
7445 bool_Print(parent.cmd.unused, *arg);
7446 }
7447
7448 if (parent.cmd.trunc != false) {
7449 cstring *arg = &ary_Alloc(args);
7450 *arg << "-trunc:";
7451 bool_Print(parent.cmd.trunc, *arg);
7452 }
7453
7454 if (parent.cmd.check != false) {
7455 cstring *arg = &ary_Alloc(args);
7456 *arg << "-check:";
7457 bool_Print(parent.cmd.check, *arg);
7458 }
7459
7460 if (parent.cmd.selerr != true) {
7461 cstring *arg = &ary_Alloc(args);
7462 *arg << "-selerr:";
7463 bool_Print(parent.cmd.selerr, *arg);
7464 }
7465
7466 if (parent.cmd.maxshow != 100) {
7467 cstring *arg = &ary_Alloc(args);
7468 *arg << "-maxshow:";
7469 i32_Print(parent.cmd.maxshow, *arg);
7470 }
7471
7472 if (parent.cmd.write != false) {
7473 cstring *arg = &ary_Alloc(args);
7474 *arg << "-write:";
7475 bool_Print(parent.cmd.write, *arg);
7476 }
7477
7478 if (parent.cmd.rename != "") {
7479 cstring *arg = &ary_Alloc(args);
7480 *arg << "-rename:";
7481 cstring_Print(parent.cmd.rename, *arg);
7482 }
7483
7484 if (parent.cmd.nup != 0) {
7485 cstring *arg = &ary_Alloc(args);
7486 *arg << "-nup:";
7487 i32_Print(parent.cmd.nup, *arg);
7488 }
7489
7490 if (parent.cmd.ndown != 0) {
7491 cstring *arg = &ary_Alloc(args);
7492 *arg << "-ndown:";
7493 i32_Print(parent.cmd.ndown, *arg);
7494 }
7495
7496 if (parent.cmd.l != false) {
7497 cstring *arg = &ary_Alloc(args);
7498 *arg << "-l:";
7499 bool_Print(parent.cmd.l, *arg);
7500 }
7501
7502 if (parent.cmd.xref != false) {
7503 cstring *arg = &ary_Alloc(args);
7504 *arg << "-xref:";
7505 bool_Print(parent.cmd.xref, *arg);
7506 }
7507
7508 if (parent.cmd.fldfunc != false) {
7509 cstring *arg = &ary_Alloc(args);
7510 *arg << "-fldfunc:";
7511 bool_Print(parent.cmd.fldfunc, *arg);
7512 }
7513
7514 if (parent.cmd.maxgroup != 25) {
7515 cstring *arg = &ary_Alloc(args);
7516 *arg << "-maxgroup:";
7517 i32_Print(parent.cmd.maxgroup, *arg);
7518 }
7519
7520 if (parent.cmd.pretty != true) {
7521 cstring *arg = &ary_Alloc(args);
7522 *arg << "-pretty:";
7523 bool_Print(parent.cmd.pretty, *arg);
7524 }
7525
7526 if (parent.cmd.tree != false) {
7527 cstring *arg = &ary_Alloc(args);
7528 *arg << "-tree:";
7529 bool_Print(parent.cmd.tree, *arg);
7530 }
7531
7532 if (parent.cmd.loose != false) {
7533 cstring *arg = &ary_Alloc(args);
7534 *arg << "-loose:";
7535 bool_Print(parent.cmd.loose, *arg);
7536 }
7537
7538 if (parent.cmd.my != false) {
7539 cstring *arg = &ary_Alloc(args);
7540 *arg << "-my:";
7541 bool_Print(parent.cmd.my, *arg);
7542 }
7543
7544 if (parent.cmd.schema != "data") {
7545 cstring *arg = &ary_Alloc(args);
7546 *arg << "-schema:";
7547 cstring_Print(parent.cmd.schema, *arg);
7548 }
7549
7550 if (parent.cmd.e != false) {
7551 cstring *arg = &ary_Alloc(args);
7552 *arg << "-e:";
7553 bool_Print(parent.cmd.e, *arg);
7554 }
7555
7556 if (parent.cmd.t != false) {
7557 cstring *arg = &ary_Alloc(args);
7558 *arg << "-t:";
7559 bool_Print(parent.cmd.t, *arg);
7560 }
7561
7562 if (parent.cmd.g != false) {
7563 cstring *arg = &ary_Alloc(args);
7564 *arg << "-g:";
7565 bool_Print(parent.cmd.g, *arg);
7566 }
7567
7568 if (parent.cmd.x != false) {
7569 cstring *arg = &ary_Alloc(args);
7570 *arg << "-x:";
7571 bool_Print(parent.cmd.x, *arg);
7572 }
7573
7574 if (parent.cmd.rowid != false) {
7575 cstring *arg = &ary_Alloc(args);
7576 *arg << "-rowid:";
7577 bool_Print(parent.cmd.rowid, *arg);
7578 }
7579
7580 if (parent.cmd.cmt != false) {
7581 cstring *arg = &ary_Alloc(args);
7582 *arg << "-cmt:";
7583 bool_Print(parent.cmd.cmt, *arg);
7584 }
7585
7586 if (parent.cmd.report != true) {
7587 cstring *arg = &ary_Alloc(args);
7588 *arg << "-report:";
7589 bool_Print(parent.cmd.report, *arg);
7590 }
7591
7592 if (parent.cmd.print != true) {
7593 cstring *arg = &ary_Alloc(args);
7594 *arg << "-print:";
7595 bool_Print(parent.cmd.print, *arg);
7596 }
7597
7598 if (parent.cmd.cmd != "") {
7599 cstring *arg = &ary_Alloc(args);
7600 *arg << "-cmd:";
7601 cstring_Print(parent.cmd.cmd, *arg);
7602 }
7603 ind_beg(command::acr_field_curs,value,parent.cmd) {
7604 cstring *arg = &ary_Alloc(args);
7605 *arg << "-field:";
7606 cstring_Print(value, *arg);
7607 }ind_end;
7608
7609 if (parent.cmd.regxof != "") {
7610 cstring *arg = &ary_Alloc(args);
7611 *arg << "-regxof:";
7612 cstring_Print(parent.cmd.regxof, *arg);
7613 }
7614
7615 if (parent.cmd.meta != false) {
7616 cstring *arg = &ary_Alloc(args);
7617 *arg << "-meta:";
7618 bool_Print(parent.cmd.meta, *arg);
7619 }
7620 for (int i=1; i < algo_lib::_db.cmdline.verbose; ++i) {
7621 ary_Alloc(args) << "-verbose";
7622 }
7623}
7624
7625// --- command.acr_proc..Uninit
7626void command::acr_proc_Uninit(command::acr_proc& parent) {
7627 command::acr_proc &row = parent; (void)row;
7628
7629 // command.acr_proc.acr.Uninit (Exec) //
7630 acr_Kill(parent); // kill child, ensure forward progress
7631}
7632
7633// --- command.amc.trace.Print
7634// Print back to string
7635void command::trace_Print(command::amc& parent, algo::cstring &out) {
7636 Regx_Print(parent.trace, out);
7637}
7638
7639// --- command.amc.trace.ReadStrptrMaybe
7640// Read Regx from string
7641// Convert string to field. Return success value
7642bool command::trace_ReadStrptrMaybe(command::amc& parent, algo::strptr in) {
7643 bool retval = true;
7644 Regx_ReadSql(parent.trace, in, true);
7645 return retval;
7646}
7647
7648// --- command.amc..ReadFieldMaybe
7649bool command::amc_ReadFieldMaybe(command::amc& parent, algo::strptr field, algo::strptr strval) {
7650 bool retval = true;
7651 command::FieldId field_id;
7652 (void)value_SetStrptrMaybe(field_id,field);
7653 switch(field_id) {
7654 case command_FieldId_in_dir: {
7655 retval = algo::cstring_ReadStrptrMaybe(parent.in_dir, strval);
7656 break;
7657 }
7658 case command_FieldId_query: {
7659 retval = algo::cstring_ReadStrptrMaybe(parent.query, strval);
7660 break;
7661 }
7662 case command_FieldId_out_dir: {
7663 retval = algo::cstring_ReadStrptrMaybe(parent.out_dir, strval);
7664 break;
7665 }
7666 case command_FieldId_proto: {
7667 retval = bool_ReadStrptrMaybe(parent.proto, strval);
7668 break;
7669 }
7670 case command_FieldId_report: {
7671 retval = bool_ReadStrptrMaybe(parent.report, strval);
7672 break;
7673 }
7674 case command_FieldId_e: {
7675 retval = bool_ReadStrptrMaybe(parent.e, strval);
7676 break;
7677 }
7678 case command_FieldId_trace: {
7679 retval = trace_ReadStrptrMaybe(parent, strval);
7680 break;
7681 }
7682 default: break;
7683 }
7684 if (!retval) {
7685 algo_lib::AppendErrtext("attr",field);
7686 }
7687 return retval;
7688}
7689
7690// --- command.amc..ReadTupleMaybe
7691// Read fields of command::amc from attributes of ascii tuple TUPLE
7692bool command::amc_ReadTupleMaybe(command::amc &parent, algo::Tuple &tuple) {
7693 bool retval = true;
7694 int anon_idx = 0;
7695 ind_beg(algo::Tuple_attrs_curs,attr,tuple) {
7696 if (ch_N(attr.name) == 0) {
7697 attr.name = amc_GetAnon(parent, anon_idx++);
7698 }
7699 retval = amc_ReadFieldMaybe(parent, attr.name, attr.value);
7700 if (!retval) {
7701 break;
7702 }
7703 }ind_end;
7704 return retval;
7705}
7706
7707// --- command.amc..Init
7708// Set all fields to initial values.
7709void command::amc_Init(command::amc& parent) {
7710 parent.in_dir = algo::strptr("data");
7711 parent.query = algo::strptr("");
7712 parent.out_dir = algo::strptr(".");
7713 parent.proto = bool(false);
7714 parent.report = bool(true);
7715 parent.e = bool(false);
7716 Regx_ReadSql(parent.trace, "", true);
7717}
7718
7719// --- command.amc..ToCmdline
7720// Convenience function that returns a full command line
7721// Assume command is in a directory called bin
7722tempstr command::amc_ToCmdline(command::amc& row) {
7723 tempstr ret;
7724 ret << "bin/amc ";
7725 amc_PrintArgv(row, ret);
7726 // inherit less intense verbose, debug options
7727 for (int i = 1; i < algo_lib::_db.cmdline.verbose; i++) {
7728 ret << " -verbose";
7729 }
7730 for (int i = 1; i < algo_lib::_db.cmdline.debug; i++) {
7731 ret << " -debug";
7732 }
7733 return ret;
7734}
7735
7736// --- command.amc..PrintArgv
7737// print string representation of ROW to string STR
7738// cfmt:command.amc.Argv printfmt:Auto
7739void command::amc_PrintArgv(command::amc& row, algo::cstring& str) {
7740 algo::tempstr temp;
7741 (void)temp;
7742 (void)str;
7743 if (!(row.in_dir == "data")) {
7744 ch_RemoveAll(temp);
7745 cstring_Print(row.in_dir, temp);
7746 str << " -in_dir:";
7747 strptr_PrintBash(temp,str);
7748 }
7749 ch_RemoveAll(temp);
7750 cstring_Print(row.query, temp);
7751 str << " -query:";
7752 strptr_PrintBash(temp,str);
7753 if (!(row.out_dir == ".")) {
7754 ch_RemoveAll(temp);
7755 cstring_Print(row.out_dir, temp);
7756 str << " -out_dir:";
7757 strptr_PrintBash(temp,str);
7758 }
7759 if (!(row.proto == false)) {
7760 ch_RemoveAll(temp);
7761 bool_Print(row.proto, temp);
7762 str << " -proto:";
7763 strptr_PrintBash(temp,str);
7764 }
7765 if (!(row.report == true)) {
7766 ch_RemoveAll(temp);
7767 bool_Print(row.report, temp);
7768 str << " -report:";
7769 strptr_PrintBash(temp,str);
7770 }
7771 if (!(row.e == false)) {
7772 ch_RemoveAll(temp);
7773 bool_Print(row.e, temp);
7774 str << " -e:";
7775 strptr_PrintBash(temp,str);
7776 }
7777 if (!(row.trace.expr == "")) {
7778 ch_RemoveAll(temp);
7779 command::trace_Print(const_cast<command::amc&>(row), temp);
7780 str << " -trace:";
7781 strptr_PrintBash(temp,str);
7782 }
7783}
7784
7785// --- command.amc..GetAnon
7786algo::strptr command::amc_GetAnon(command::amc &parent, i32 idx) {
7787 (void)parent;//only to avoid -Wunused-parameter
7788 switch(idx) {
7789 case(0): return strptr("query", 5);
7790 default: return algo::strptr();
7791 }
7792}
7793
7794// --- command.amc..NArgs
7795// Used with command lines
7796// Return # of command-line arguments that must follow this argument
7797// If FIELD is invalid, return -1
7798i32 command::amc_NArgs(command::FieldId field, algo::strptr& out_dflt, bool* out_anon) {
7799 i32 retval = 1;
7800 switch (field) {
7801 case command_FieldId_in_dir: { // $comment
7802 *out_anon = false;
7803 } break;
7804 case command_FieldId_query: { // $comment
7805 *out_anon = true;
7806 } break;
7807 case command_FieldId_out_dir: { // $comment
7808 *out_anon = false;
7809 } break;
7810 case command_FieldId_proto: { // $comment
7811 *out_anon = false;
7812 retval=0;
7813 out_dflt="Y";
7814 } break;
7815 case command_FieldId_report: { // bool: no argument required but value may be specified as proto:Y
7816 *out_anon = false;
7817 retval=0;
7818 out_dflt="Y";
7819 } break;
7820 case command_FieldId_e: { // bool: no argument required but value may be specified as report:Y
7821 *out_anon = false;
7822 retval=0;
7823 out_dflt="Y";
7824 } break;
7825 case command_FieldId_trace: { // bool: no argument required but value may be specified as e:Y
7826 *out_anon = false;
7827 } break;
7828 default:
7829 retval=-1; // unrecognized
7830 }
7831 return retval;
7832}
7833
7834// --- command.amc_gc.target.Print
7835// Print back to string
7836void command::target_Print(command::amc_gc& parent, algo::cstring &out) {
7837 Regx_Print(parent.target, out);
7838}
7839
7840// --- command.amc_gc.target.ReadStrptrMaybe
7841// Read Regx from string
7842// Convert string to field. Return success value
7843bool command::target_ReadStrptrMaybe(command::amc_gc& parent, algo::strptr in) {
7844 bool retval = true;
7845 Regx_ReadSql(parent.target, in, true);
7846 return retval;
7847}
7848
7849// --- command.amc_gc.key.Print
7850// Print back to string
7851void command::key_Print(command::amc_gc& parent, algo::cstring &out) {
7852 Regx_Print(parent.key, out);
7853}
7854
7855// --- command.amc_gc.key.ReadStrptrMaybe
7856// Read Regx from string
7857// Convert string to field. Return success value
7858bool command::key_ReadStrptrMaybe(command::amc_gc& parent, algo::strptr in) {
7859 bool retval = true;
7860 Regx_ReadSql(parent.key, in, true);
7861 return retval;
7862}
7863
7864// --- command.amc_gc..ReadFieldMaybe
7865bool command::amc_gc_ReadFieldMaybe(command::amc_gc& parent, algo::strptr field, algo::strptr strval) {
7866 bool retval = true;
7867 command::FieldId field_id;
7868 (void)value_SetStrptrMaybe(field_id,field);
7869 switch(field_id) {
7870 case command_FieldId_target: {
7871 retval = target_ReadStrptrMaybe(parent, strval);
7872 break;
7873 }
7874 case command_FieldId_key: {
7875 retval = key_ReadStrptrMaybe(parent, strval);
7876 break;
7877 }
7878 case command_FieldId_include: {
7879 retval = bool_ReadStrptrMaybe(parent.include, strval);
7880 break;
7881 }
7882 case command_FieldId_in: {
7883 retval = algo::cstring_ReadStrptrMaybe(parent.in, strval);
7884 break;
7885 }
7886 default: break;
7887 }
7888 if (!retval) {
7889 algo_lib::AppendErrtext("attr",field);
7890 }
7891 return retval;
7892}
7893
7894// --- command.amc_gc..ReadTupleMaybe
7895// Read fields of command::amc_gc from attributes of ascii tuple TUPLE
7896bool command::amc_gc_ReadTupleMaybe(command::amc_gc &parent, algo::Tuple &tuple) {
7897 bool retval = true;
7898 ind_beg(algo::Tuple_attrs_curs,attr,tuple) {
7899 retval = amc_gc_ReadFieldMaybe(parent, attr.name, attr.value);
7900 if (!retval) {
7901 break;
7902 }
7903 }ind_end;
7904 return retval;
7905}
7906
7907// --- command.amc_gc..Init
7908// Set all fields to initial values.
7909void command::amc_gc_Init(command::amc_gc& parent) {
7910 Regx_ReadSql(parent.target, "%", true);
7911 Regx_ReadSql(parent.key, "", true);
7912 parent.include = bool(false);
7913 parent.in = algo::strptr("data");
7914}
7915
7916// --- command.amc_gc..ToCmdline
7917// Convenience function that returns a full command line
7918// Assume command is in a directory called bin
7919tempstr command::amc_gc_ToCmdline(command::amc_gc& row) {
7920 tempstr ret;
7921 ret << "bin/amc_gc ";
7922 amc_gc_PrintArgv(row, ret);
7923 // inherit less intense verbose, debug options
7924 for (int i = 1; i < algo_lib::_db.cmdline.verbose; i++) {
7925 ret << " -verbose";
7926 }
7927 for (int i = 1; i < algo_lib::_db.cmdline.debug; i++) {
7928 ret << " -debug";
7929 }
7930 return ret;
7931}
7932
7933// --- command.amc_gc..PrintArgv
7934// print string representation of ROW to string STR
7935// cfmt:command.amc_gc.Argv printfmt:Tuple
7936void command::amc_gc_PrintArgv(command::amc_gc& row, algo::cstring& str) {
7937 algo::tempstr temp;
7938 (void)temp;
7939 (void)str;
7940 if (!(row.target.expr == "%")) {
7941 ch_RemoveAll(temp);
7942 command::target_Print(const_cast<command::amc_gc&>(row), temp);
7943 str << " -target:";
7944 strptr_PrintBash(temp,str);
7945 }
7946 if (!(row.key.expr == "")) {
7947 ch_RemoveAll(temp);
7948 command::key_Print(const_cast<command::amc_gc&>(row), temp);
7949 str << " -key:";
7950 strptr_PrintBash(temp,str);
7951 }
7952 if (!(row.include == false)) {
7953 ch_RemoveAll(temp);
7954 bool_Print(row.include, temp);
7955 str << " -include:";
7956 strptr_PrintBash(temp,str);
7957 }
7958 if (!(row.in == "data")) {
7959 ch_RemoveAll(temp);
7960 cstring_Print(row.in, temp);
7961 str << " -in:";
7962 strptr_PrintBash(temp,str);
7963 }
7964}
7965
7966// --- command.amc_gc..NArgs
7967// Used with command lines
7968// Return # of command-line arguments that must follow this argument
7969// If FIELD is invalid, return -1
7970i32 command::amc_gc_NArgs(command::FieldId field, algo::strptr& out_dflt, bool* out_anon) {
7971 i32 retval = 1;
7972 switch (field) {
7973 case command_FieldId_target: { // $comment
7974 *out_anon = false;
7975 } break;
7976 case command_FieldId_key: { // $comment
7977 *out_anon = false;
7978 } break;
7979 case command_FieldId_include: { // $comment
7980 *out_anon = false;
7981 retval=0;
7982 out_dflt="Y";
7983 } break;
7984 case command_FieldId_in: { // bool: no argument required but value may be specified as include:Y
7985 *out_anon = false;
7986 } break;
7987 default:
7988 retval=-1; // unrecognized
7989 }
7990 return retval;
7991}
7992
7993// --- command.amc_gc_proc.amc_gc.Start
7994// Start subprocess
7995// If subprocess already running, do nothing. Otherwise, start it
7996int command::amc_gc_Start(command::amc_gc_proc& parent) {
7997 int retval = 0;
7998 if (parent.pid == 0) {
7999 verblog(amc_gc_ToCmdline(parent)); // maybe print command
8000#ifdef WIN32
8001 algo_lib::ResolveExecFname(parent.path);
8002 tempstr cmdline(amc_gc_ToCmdline(parent));
8003 parent.pid = dospawn(Zeroterm(parent.path),Zeroterm(cmdline),parent.timeout,parent.fstdin,parent.fstdout,parent.fstderr);
8004#else
8005 parent.pid = fork();
8006 if (parent.pid == 0) { // child
8007 algo_lib::DieWithParent();
8008 if (parent.timeout > 0) {
8009 alarm(parent.timeout);
8010 }
8011 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstdin , 0);
8012 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstdout, 1);
8013 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstderr, 2);
8014 if (retval==0) retval= amc_gc_Execv(parent);
8015 if (retval != 0) { // if start fails, print error
8016 int err=errno;
8017 prerr("command.amc_gc_execv"
8018 <<Keyval("errno",err)
8019 <<Keyval("errstr",strerror(err))
8020 <<Keyval("comment","Execv failed"));
8021 }
8022 _exit(127); // if failed to start, exit anyway
8023 } else if (parent.pid == -1) {
8024 retval = errno; // failed to fork
8025 }
8026#endif
8027 }
8028 parent.status = parent.pid > 0 ? 0 : -1; // if didn't start, set error status
8029 return retval;
8030}
8031
8032// --- command.amc_gc_proc.amc_gc.StartRead
8033// Start subprocess & Read output
8034algo::Fildes command::amc_gc_StartRead(command::amc_gc_proc& parent, algo_lib::FFildes &read) {
8035 int pipefd[2];
8036 int rc=pipe(pipefd);
8037 (void)rc;
8038 read.fd.value = pipefd[0];
8039 parent.fstdout << ">&" << pipefd[1];
8040 amc_gc_Start(parent);
8041 (void)close(pipefd[1]);
8042 return read.fd;
8043}
8044
8045// --- command.amc_gc_proc.amc_gc.Kill
8046// Kill subprocess and wait
8047void command::amc_gc_Kill(command::amc_gc_proc& parent) {
8048 if (parent.pid != 0) {
8049 kill(parent.pid,9);
8050 amc_gc_Wait(parent);
8051 }
8052}
8053
8054// --- command.amc_gc_proc.amc_gc.Wait
8055// Wait for subprocess to return
8056void command::amc_gc_Wait(command::amc_gc_proc& parent) {
8057 if (parent.pid > 0) {
8058 int wait_flags = 0;
8059 int wait_status = 0;
8060 int rc = -1;
8061 do {
8062 // really wait for subprocess to exit
8063 rc = waitpid(parent.pid,&wait_status,wait_flags);
8064 } while (rc==-1 && errno==EINTR);
8065 if (rc == parent.pid) {
8066 parent.status = wait_status;
8067 parent.pid = 0;
8068 }
8069 }
8070}
8071
8072// --- command.amc_gc_proc.amc_gc.Exec
8073// Start + Wait
8074// Execute subprocess and return exit code
8075int command::amc_gc_Exec(command::amc_gc_proc& parent) {
8076 amc_gc_Start(parent);
8077 amc_gc_Wait(parent);
8078 return parent.status;
8079}
8080
8081// --- command.amc_gc_proc.amc_gc.ExecX
8082// Start + Wait, throw exception on error
8083// Execute subprocess; throw human-readable exception on error
8084void command::amc_gc_ExecX(command::amc_gc_proc& parent) {
8085 int rc = amc_gc_Exec(parent);
8086 vrfy(rc==0, tempstr() << "algo_lib.exec" << Keyval("cmd",amc_gc_ToCmdline(parent))
8087 << Keyval("comment",algo::DescribeWaitStatus(parent.status)));
8088}
8089
8090// --- command.amc_gc_proc.amc_gc.Execv
8091// Call execv()
8092// Call execv with specified parameters
8093int command::amc_gc_Execv(command::amc_gc_proc& parent) {
8094 int ret = 0;
8095 algo::StringAry args;
8096 amc_gc_ToArgv(parent, args);
8097 char **argv = (char**)alloca((ary_N(args)+1)*sizeof(*argv));
8098 ind_beg(algo::StringAry_ary_curs,arg,args) {
8099 argv[ind_curs(arg).index] = Zeroterm(arg);
8100 }ind_end;
8101 argv[ary_N(args)] = NULL;
8102 // if parent.path is relative, search for it in PATH
8103 algo_lib::ResolveExecFname(parent.path);
8104 ret = execv(Zeroterm(parent.path),argv);
8105 return ret;
8106}
8107
8108// --- command.amc_gc_proc.amc_gc.ToCmdline
8109algo::tempstr command::amc_gc_ToCmdline(command::amc_gc_proc& parent) {
8110 algo::tempstr retval;
8111 retval << parent.path << " ";
8112 command::amc_gc_PrintArgv(parent.cmd,retval);
8113 if (ch_N(parent.fstdin)) {
8114 retval << " " << parent.fstdin;
8115 }
8116 if (ch_N(parent.fstdout)) {
8117 retval << " " << parent.fstdout;
8118 }
8119 if (ch_N(parent.fstderr)) {
8120 retval << " 2" << parent.fstderr;
8121 }
8122 return retval;
8123}
8124
8125// --- command.amc_gc_proc.amc_gc.ToArgv
8126// Form array from the command line
8127void command::amc_gc_ToArgv(command::amc_gc_proc& parent, algo::StringAry& args) {
8128 ary_RemoveAll(args);
8129 ary_Alloc(args) << parent.path;
8130
8131 if (parent.cmd.target.expr != "%") {
8132 cstring *arg = &ary_Alloc(args);
8133 *arg << "-target:";
8134 command::target_Print(parent.cmd, *arg);
8135 }
8136
8137 if (parent.cmd.key.expr != "") {
8138 cstring *arg = &ary_Alloc(args);
8139 *arg << "-key:";
8140 command::key_Print(parent.cmd, *arg);
8141 }
8142
8143 if (parent.cmd.include != false) {
8144 cstring *arg = &ary_Alloc(args);
8145 *arg << "-include:";
8146 bool_Print(parent.cmd.include, *arg);
8147 }
8148
8149 if (parent.cmd.in != "data") {
8150 cstring *arg = &ary_Alloc(args);
8151 *arg << "-in:";
8152 cstring_Print(parent.cmd.in, *arg);
8153 }
8154 for (int i=1; i < algo_lib::_db.cmdline.verbose; ++i) {
8155 ary_Alloc(args) << "-verbose";
8156 }
8157}
8158
8159// --- command.amc_gc_proc..Uninit
8160void command::amc_gc_proc_Uninit(command::amc_gc_proc& parent) {
8161 command::amc_gc_proc &row = parent; (void)row;
8162
8163 // command.amc_gc_proc.amc_gc.Uninit (Exec) //
8164 amc_gc_Kill(parent); // kill child, ensure forward progress
8165}
8166
8167// --- command.amc_js..ReadFieldMaybe
8168bool command::amc_js_ReadFieldMaybe(command::amc_js& parent, algo::strptr field, algo::strptr strval) {
8169 bool retval = true;
8170 command::FieldId field_id;
8171 (void)value_SetStrptrMaybe(field_id,field);
8172 switch(field_id) {
8173 case command_FieldId_in: {
8174 retval = algo::cstring_ReadStrptrMaybe(parent.in, strval);
8175 break;
8176 }
8177 default: break;
8178 }
8179 if (!retval) {
8180 algo_lib::AppendErrtext("attr",field);
8181 }
8182 return retval;
8183}
8184
8185// --- command.amc_js..ReadTupleMaybe
8186// Read fields of command::amc_js from attributes of ascii tuple TUPLE
8187bool command::amc_js_ReadTupleMaybe(command::amc_js &parent, algo::Tuple &tuple) {
8188 bool retval = true;
8189 ind_beg(algo::Tuple_attrs_curs,attr,tuple) {
8190 retval = amc_js_ReadFieldMaybe(parent, attr.name, attr.value);
8191 if (!retval) {
8192 break;
8193 }
8194 }ind_end;
8195 return retval;
8196}
8197
8198// --- command.amc_js..ToCmdline
8199// Convenience function that returns a full command line
8200// Assume command is in a directory called bin
8201tempstr command::amc_js_ToCmdline(command::amc_js& row) {
8202 tempstr ret;
8203 ret << "bin/amc_js ";
8204 amc_js_PrintArgv(row, ret);
8205 // inherit less intense verbose, debug options
8206 for (int i = 1; i < algo_lib::_db.cmdline.verbose; i++) {
8207 ret << " -verbose";
8208 }
8209 for (int i = 1; i < algo_lib::_db.cmdline.debug; i++) {
8210 ret << " -debug";
8211 }
8212 return ret;
8213}
8214
8215// --- command.amc_js..PrintArgv
8216// print string representation of ROW to string STR
8217// cfmt:command.amc_js.Argv printfmt:Tuple
8218void command::amc_js_PrintArgv(command::amc_js& row, algo::cstring& str) {
8219 algo::tempstr temp;
8220 (void)temp;
8221 (void)str;
8222 if (!(row.in == "data")) {
8223 ch_RemoveAll(temp);
8224 cstring_Print(row.in, temp);
8225 str << " -in:";
8226 strptr_PrintBash(temp,str);
8227 }
8228}
8229
8230// --- command.amc_js..NArgs
8231// Used with command lines
8232// Return # of command-line arguments that must follow this argument
8233// If FIELD is invalid, return -1
8234i32 command::amc_js_NArgs(command::FieldId field, algo::strptr& out_dflt, bool* out_anon) {
8235 i32 retval = 1;
8236 switch (field) {
8237 case command_FieldId_in: { // $comment
8238 *out_anon = false;
8239 } break;
8240 default:
8241 retval=-1; // unrecognized
8242 }
8243 (void)out_dflt;//only to avoid -Wunused-parameter
8244 return retval;
8245}
8246
8247// --- command.amc_js_proc.amc_js.Start
8248// Start subprocess
8249// If subprocess already running, do nothing. Otherwise, start it
8250int command::amc_js_Start(command::amc_js_proc& parent) {
8251 int retval = 0;
8252 if (parent.pid == 0) {
8253 verblog(amc_js_ToCmdline(parent)); // maybe print command
8254#ifdef WIN32
8255 algo_lib::ResolveExecFname(parent.path);
8256 tempstr cmdline(amc_js_ToCmdline(parent));
8257 parent.pid = dospawn(Zeroterm(parent.path),Zeroterm(cmdline),parent.timeout,parent.fstdin,parent.fstdout,parent.fstderr);
8258#else
8259 parent.pid = fork();
8260 if (parent.pid == 0) { // child
8261 algo_lib::DieWithParent();
8262 if (parent.timeout > 0) {
8263 alarm(parent.timeout);
8264 }
8265 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstdin , 0);
8266 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstdout, 1);
8267 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstderr, 2);
8268 if (retval==0) retval= amc_js_Execv(parent);
8269 if (retval != 0) { // if start fails, print error
8270 int err=errno;
8271 prerr("command.amc_js_execv"
8272 <<Keyval("errno",err)
8273 <<Keyval("errstr",strerror(err))
8274 <<Keyval("comment","Execv failed"));
8275 }
8276 _exit(127); // if failed to start, exit anyway
8277 } else if (parent.pid == -1) {
8278 retval = errno; // failed to fork
8279 }
8280#endif
8281 }
8282 parent.status = parent.pid > 0 ? 0 : -1; // if didn't start, set error status
8283 return retval;
8284}
8285
8286// --- command.amc_js_proc.amc_js.StartRead
8287// Start subprocess & Read output
8288algo::Fildes command::amc_js_StartRead(command::amc_js_proc& parent, algo_lib::FFildes &read) {
8289 int pipefd[2];
8290 int rc=pipe(pipefd);
8291 (void)rc;
8292 read.fd.value = pipefd[0];
8293 parent.fstdout << ">&" << pipefd[1];
8294 amc_js_Start(parent);
8295 (void)close(pipefd[1]);
8296 return read.fd;
8297}
8298
8299// --- command.amc_js_proc.amc_js.Kill
8300// Kill subprocess and wait
8301void command::amc_js_Kill(command::amc_js_proc& parent) {
8302 if (parent.pid != 0) {
8303 kill(parent.pid,9);
8304 amc_js_Wait(parent);
8305 }
8306}
8307
8308// --- command.amc_js_proc.amc_js.Wait
8309// Wait for subprocess to return
8310void command::amc_js_Wait(command::amc_js_proc& parent) {
8311 if (parent.pid > 0) {
8312 int wait_flags = 0;
8313 int wait_status = 0;
8314 int rc = -1;
8315 do {
8316 // really wait for subprocess to exit
8317 rc = waitpid(parent.pid,&wait_status,wait_flags);
8318 } while (rc==-1 && errno==EINTR);
8319 if (rc == parent.pid) {
8320 parent.status = wait_status;
8321 parent.pid = 0;
8322 }
8323 }
8324}
8325
8326// --- command.amc_js_proc.amc_js.Exec
8327// Start + Wait
8328// Execute subprocess and return exit code
8329int command::amc_js_Exec(command::amc_js_proc& parent) {
8330 amc_js_Start(parent);
8331 amc_js_Wait(parent);
8332 return parent.status;
8333}
8334
8335// --- command.amc_js_proc.amc_js.ExecX
8336// Start + Wait, throw exception on error
8337// Execute subprocess; throw human-readable exception on error
8338void command::amc_js_ExecX(command::amc_js_proc& parent) {
8339 int rc = amc_js_Exec(parent);
8340 vrfy(rc==0, tempstr() << "algo_lib.exec" << Keyval("cmd",amc_js_ToCmdline(parent))
8341 << Keyval("comment",algo::DescribeWaitStatus(parent.status)));
8342}
8343
8344// --- command.amc_js_proc.amc_js.Execv
8345// Call execv()
8346// Call execv with specified parameters
8347int command::amc_js_Execv(command::amc_js_proc& parent) {
8348 int ret = 0;
8349 algo::StringAry args;
8350 amc_js_ToArgv(parent, args);
8351 char **argv = (char**)alloca((ary_N(args)+1)*sizeof(*argv));
8352 ind_beg(algo::StringAry_ary_curs,arg,args) {
8353 argv[ind_curs(arg).index] = Zeroterm(arg);
8354 }ind_end;
8355 argv[ary_N(args)] = NULL;
8356 // if parent.path is relative, search for it in PATH
8357 algo_lib::ResolveExecFname(parent.path);
8358 ret = execv(Zeroterm(parent.path),argv);
8359 return ret;
8360}
8361
8362// --- command.amc_js_proc.amc_js.ToCmdline
8363algo::tempstr command::amc_js_ToCmdline(command::amc_js_proc& parent) {
8364 algo::tempstr retval;
8365 retval << parent.path << " ";
8366 command::amc_js_PrintArgv(parent.cmd,retval);
8367 if (ch_N(parent.fstdin)) {
8368 retval << " " << parent.fstdin;
8369 }
8370 if (ch_N(parent.fstdout)) {
8371 retval << " " << parent.fstdout;
8372 }
8373 if (ch_N(parent.fstderr)) {
8374 retval << " 2" << parent.fstderr;
8375 }
8376 return retval;
8377}
8378
8379// --- command.amc_js_proc.amc_js.ToArgv
8380// Form array from the command line
8381void command::amc_js_ToArgv(command::amc_js_proc& parent, algo::StringAry& args) {
8382 ary_RemoveAll(args);
8383 ary_Alloc(args) << parent.path;
8384
8385 if (parent.cmd.in != "data") {
8386 cstring *arg = &ary_Alloc(args);
8387 *arg << "-in:";
8388 cstring_Print(parent.cmd.in, *arg);
8389 }
8390 for (int i=1; i < algo_lib::_db.cmdline.verbose; ++i) {
8391 ary_Alloc(args) << "-verbose";
8392 }
8393}
8394
8395// --- command.amc_js_proc..Uninit
8396void command::amc_js_proc_Uninit(command::amc_js_proc& parent) {
8397 command::amc_js_proc &row = parent; (void)row;
8398
8399 // command.amc_js_proc.amc_js.Uninit (Exec) //
8400 amc_js_Kill(parent); // kill child, ensure forward progress
8401}
8402
8403// --- command.amc_proc.amc.Start
8404// Start subprocess
8405// If subprocess already running, do nothing. Otherwise, start it
8406int command::amc_Start(command::amc_proc& parent) {
8407 int retval = 0;
8408 if (parent.pid == 0) {
8409 verblog(amc_ToCmdline(parent)); // maybe print command
8410#ifdef WIN32
8411 algo_lib::ResolveExecFname(parent.path);
8412 tempstr cmdline(amc_ToCmdline(parent));
8413 parent.pid = dospawn(Zeroterm(parent.path),Zeroterm(cmdline),parent.timeout,parent.fstdin,parent.fstdout,parent.fstderr);
8414#else
8415 parent.pid = fork();
8416 if (parent.pid == 0) { // child
8417 algo_lib::DieWithParent();
8418 if (parent.timeout > 0) {
8419 alarm(parent.timeout);
8420 }
8421 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstdin , 0);
8422 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstdout, 1);
8423 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstderr, 2);
8424 if (retval==0) retval= amc_Execv(parent);
8425 if (retval != 0) { // if start fails, print error
8426 int err=errno;
8427 prerr("command.amc_execv"
8428 <<Keyval("errno",err)
8429 <<Keyval("errstr",strerror(err))
8430 <<Keyval("comment","Execv failed"));
8431 }
8432 _exit(127); // if failed to start, exit anyway
8433 } else if (parent.pid == -1) {
8434 retval = errno; // failed to fork
8435 }
8436#endif
8437 }
8438 parent.status = parent.pid > 0 ? 0 : -1; // if didn't start, set error status
8439 return retval;
8440}
8441
8442// --- command.amc_proc.amc.StartRead
8443// Start subprocess & Read output
8444algo::Fildes command::amc_StartRead(command::amc_proc& parent, algo_lib::FFildes &read) {
8445 int pipefd[2];
8446 int rc=pipe(pipefd);
8447 (void)rc;
8448 read.fd.value = pipefd[0];
8449 parent.fstdout << ">&" << pipefd[1];
8450 amc_Start(parent);
8451 (void)close(pipefd[1]);
8452 return read.fd;
8453}
8454
8455// --- command.amc_proc.amc.Kill
8456// Kill subprocess and wait
8457void command::amc_Kill(command::amc_proc& parent) {
8458 if (parent.pid != 0) {
8459 kill(parent.pid,9);
8460 amc_Wait(parent);
8461 }
8462}
8463
8464// --- command.amc_proc.amc.Wait
8465// Wait for subprocess to return
8466void command::amc_Wait(command::amc_proc& parent) {
8467 if (parent.pid > 0) {
8468 int wait_flags = 0;
8469 int wait_status = 0;
8470 int rc = -1;
8471 do {
8472 // really wait for subprocess to exit
8473 rc = waitpid(parent.pid,&wait_status,wait_flags);
8474 } while (rc==-1 && errno==EINTR);
8475 if (rc == parent.pid) {
8476 parent.status = wait_status;
8477 parent.pid = 0;
8478 }
8479 }
8480}
8481
8482// --- command.amc_proc.amc.Exec
8483// Start + Wait
8484// Execute subprocess and return exit code
8485int command::amc_Exec(command::amc_proc& parent) {
8486 amc_Start(parent);
8487 amc_Wait(parent);
8488 return parent.status;
8489}
8490
8491// --- command.amc_proc.amc.ExecX
8492// Start + Wait, throw exception on error
8493// Execute subprocess; throw human-readable exception on error
8494void command::amc_ExecX(command::amc_proc& parent) {
8495 int rc = amc_Exec(parent);
8496 vrfy(rc==0, tempstr() << "algo_lib.exec" << Keyval("cmd",amc_ToCmdline(parent))
8497 << Keyval("comment",algo::DescribeWaitStatus(parent.status)));
8498}
8499
8500// --- command.amc_proc.amc.Execv
8501// Call execv()
8502// Call execv with specified parameters
8503int command::amc_Execv(command::amc_proc& parent) {
8504 int ret = 0;
8505 algo::StringAry args;
8506 amc_ToArgv(parent, args);
8507 char **argv = (char**)alloca((ary_N(args)+1)*sizeof(*argv));
8508 ind_beg(algo::StringAry_ary_curs,arg,args) {
8509 argv[ind_curs(arg).index] = Zeroterm(arg);
8510 }ind_end;
8511 argv[ary_N(args)] = NULL;
8512 // if parent.path is relative, search for it in PATH
8513 algo_lib::ResolveExecFname(parent.path);
8514 ret = execv(Zeroterm(parent.path),argv);
8515 return ret;
8516}
8517
8518// --- command.amc_proc.amc.ToCmdline
8519algo::tempstr command::amc_ToCmdline(command::amc_proc& parent) {
8520 algo::tempstr retval;
8521 retval << parent.path << " ";
8522 command::amc_PrintArgv(parent.cmd,retval);
8523 if (ch_N(parent.fstdin)) {
8524 retval << " " << parent.fstdin;
8525 }
8526 if (ch_N(parent.fstdout)) {
8527 retval << " " << parent.fstdout;
8528 }
8529 if (ch_N(parent.fstderr)) {
8530 retval << " 2" << parent.fstderr;
8531 }
8532 return retval;
8533}
8534
8535// --- command.amc_proc.amc.ToArgv
8536// Form array from the command line
8537void command::amc_ToArgv(command::amc_proc& parent, algo::StringAry& args) {
8538 ary_RemoveAll(args);
8539 ary_Alloc(args) << parent.path;
8540
8541 if (parent.cmd.in_dir != "data") {
8542 cstring *arg = &ary_Alloc(args);
8543 *arg << "-in_dir:";
8544 cstring_Print(parent.cmd.in_dir, *arg);
8545 }
8546
8547 if (parent.cmd.query != "") {
8548 cstring *arg = &ary_Alloc(args);
8549 *arg << "-query:";
8550 cstring_Print(parent.cmd.query, *arg);
8551 }
8552
8553 if (parent.cmd.out_dir != ".") {
8554 cstring *arg = &ary_Alloc(args);
8555 *arg << "-out_dir:";
8556 cstring_Print(parent.cmd.out_dir, *arg);
8557 }
8558
8559 if (parent.cmd.proto != false) {
8560 cstring *arg = &ary_Alloc(args);
8561 *arg << "-proto:";
8562 bool_Print(parent.cmd.proto, *arg);
8563 }
8564
8565 if (parent.cmd.report != true) {
8566 cstring *arg = &ary_Alloc(args);
8567 *arg << "-report:";
8568 bool_Print(parent.cmd.report, *arg);
8569 }
8570
8571 if (parent.cmd.e != false) {
8572 cstring *arg = &ary_Alloc(args);
8573 *arg << "-e:";
8574 bool_Print(parent.cmd.e, *arg);
8575 }
8576
8577 if (parent.cmd.trace.expr != "") {
8578 cstring *arg = &ary_Alloc(args);
8579 *arg << "-trace:";
8580 command::trace_Print(parent.cmd, *arg);
8581 }
8582 for (int i=1; i < algo_lib::_db.cmdline.verbose; ++i) {
8583 ary_Alloc(args) << "-verbose";
8584 }
8585}
8586
8587// --- command.amc_proc..Uninit
8588void command::amc_proc_Uninit(command::amc_proc& parent) {
8589 command::amc_proc &row = parent; (void)row;
8590
8591 // command.amc_proc.amc.Uninit (Exec) //
8592 amc_Kill(parent); // kill child, ensure forward progress
8593}
8594
8595// --- command.amc_vis.ctype.Print
8596// Print back to string
8597void command::ctype_Print(command::amc_vis& parent, algo::cstring &out) {
8598 Regx_Print(parent.ctype, out);
8599}
8600
8601// --- command.amc_vis.ctype.ReadStrptrMaybe
8602// Read Regx from string
8603// Convert string to field. Return success value
8604bool command::ctype_ReadStrptrMaybe(command::amc_vis& parent, algo::strptr in) {
8605 bool retval = true;
8606 Regx_ReadSql(parent.ctype, in, true);
8607 return retval;
8608}
8609
8610// --- command.amc_vis..ReadFieldMaybe
8611bool command::amc_vis_ReadFieldMaybe(command::amc_vis& parent, algo::strptr field, algo::strptr strval) {
8612 bool retval = true;
8613 command::FieldId field_id;
8614 (void)value_SetStrptrMaybe(field_id,field);
8615 switch(field_id) {
8616 case command_FieldId_ctype: {
8617 retval = ctype_ReadStrptrMaybe(parent, strval);
8618 break;
8619 }
8620 case command_FieldId_in: {
8621 retval = algo::cstring_ReadStrptrMaybe(parent.in, strval);
8622 break;
8623 }
8624 case command_FieldId_dot: {
8625 retval = algo::cstring_ReadStrptrMaybe(parent.dot, strval);
8626 break;
8627 }
8628 case command_FieldId_xref: {
8629 retval = bool_ReadStrptrMaybe(parent.xref, strval);
8630 break;
8631 }
8632 case command_FieldId_xns: {
8633 retval = bool_ReadStrptrMaybe(parent.xns, strval);
8634 break;
8635 }
8636 case command_FieldId_noinput: {
8637 retval = bool_ReadStrptrMaybe(parent.noinput, strval);
8638 break;
8639 }
8640 case command_FieldId_check: {
8641 retval = bool_ReadStrptrMaybe(parent.check, strval);
8642 break;
8643 }
8644 case command_FieldId_render: {
8645 retval = bool_ReadStrptrMaybe(parent.render, strval);
8646 break;
8647 }
8648 default: break;
8649 }
8650 if (!retval) {
8651 algo_lib::AppendErrtext("attr",field);
8652 }
8653 return retval;
8654}
8655
8656// --- command.amc_vis..ReadTupleMaybe
8657// Read fields of command::amc_vis from attributes of ascii tuple TUPLE
8658bool command::amc_vis_ReadTupleMaybe(command::amc_vis &parent, algo::Tuple &tuple) {
8659 bool retval = true;
8660 int anon_idx = 0;
8661 ind_beg(algo::Tuple_attrs_curs,attr,tuple) {
8662 if (ch_N(attr.name) == 0) {
8663 attr.name = amc_vis_GetAnon(parent, anon_idx++);
8664 }
8665 retval = amc_vis_ReadFieldMaybe(parent, attr.name, attr.value);
8666 if (!retval) {
8667 break;
8668 }
8669 }ind_end;
8670 return retval;
8671}
8672
8673// --- command.amc_vis..Init
8674// Set all fields to initial values.
8675void command::amc_vis_Init(command::amc_vis& parent) {
8676 Regx_ReadSql(parent.ctype, "%", true);
8677 parent.in = algo::strptr("data");
8678 parent.dot = algo::strptr("");
8679 parent.xref = bool(false);
8680 parent.xns = bool(false);
8681 parent.noinput = bool(false);
8682 parent.check = bool(false);
8683 parent.render = bool(true);
8684}
8685
8686// --- command.amc_vis..ToCmdline
8687// Convenience function that returns a full command line
8688// Assume command is in a directory called bin
8689tempstr command::amc_vis_ToCmdline(command::amc_vis& row) {
8690 tempstr ret;
8691 ret << "bin/amc_vis ";
8692 amc_vis_PrintArgv(row, ret);
8693 // inherit less intense verbose, debug options
8694 for (int i = 1; i < algo_lib::_db.cmdline.verbose; i++) {
8695 ret << " -verbose";
8696 }
8697 for (int i = 1; i < algo_lib::_db.cmdline.debug; i++) {
8698 ret << " -debug";
8699 }
8700 return ret;
8701}
8702
8703// --- command.amc_vis..PrintArgv
8704// print string representation of ROW to string STR
8705// cfmt:command.amc_vis.Argv printfmt:Auto
8706void command::amc_vis_PrintArgv(command::amc_vis& row, algo::cstring& str) {
8707 algo::tempstr temp;
8708 (void)temp;
8709 (void)str;
8710 ch_RemoveAll(temp);
8711 command::ctype_Print(const_cast<command::amc_vis&>(row), temp);
8712 str << " -ctype:";
8713 strptr_PrintBash(temp,str);
8714 if (!(row.in == "data")) {
8715 ch_RemoveAll(temp);
8716 cstring_Print(row.in, temp);
8717 str << " -in:";
8718 strptr_PrintBash(temp,str);
8719 }
8720 if (!(row.dot == "")) {
8721 ch_RemoveAll(temp);
8722 cstring_Print(row.dot, temp);
8723 str << " -dot:";
8724 strptr_PrintBash(temp,str);
8725 }
8726 if (!(row.xref == false)) {
8727 ch_RemoveAll(temp);
8728 bool_Print(row.xref, temp);
8729 str << " -xref:";
8730 strptr_PrintBash(temp,str);
8731 }
8732 if (!(row.xns == false)) {
8733 ch_RemoveAll(temp);
8734 bool_Print(row.xns, temp);
8735 str << " -xns:";
8736 strptr_PrintBash(temp,str);
8737 }
8738 if (!(row.noinput == false)) {
8739 ch_RemoveAll(temp);
8740 bool_Print(row.noinput, temp);
8741 str << " -noinput:";
8742 strptr_PrintBash(temp,str);
8743 }
8744 if (!(row.check == false)) {
8745 ch_RemoveAll(temp);
8746 bool_Print(row.check, temp);
8747 str << " -check:";
8748 strptr_PrintBash(temp,str);
8749 }
8750 if (!(row.render == true)) {
8751 ch_RemoveAll(temp);
8752 bool_Print(row.render, temp);
8753 str << " -render:";
8754 strptr_PrintBash(temp,str);
8755 }
8756}
8757
8758// --- command.amc_vis..GetAnon
8759algo::strptr command::amc_vis_GetAnon(command::amc_vis &parent, i32 idx) {
8760 (void)parent;//only to avoid -Wunused-parameter
8761 switch(idx) {
8762 case(0): return strptr("ctype", 5);
8763 default: return algo::strptr();
8764 }
8765}
8766
8767// --- command.amc_vis..NArgs
8768// Used with command lines
8769// Return # of command-line arguments that must follow this argument
8770// If FIELD is invalid, return -1
8771i32 command::amc_vis_NArgs(command::FieldId field, algo::strptr& out_dflt, bool* out_anon) {
8772 i32 retval = 1;
8773 switch (field) {
8774 case command_FieldId_ctype: { // $comment
8775 *out_anon = true;
8776 } break;
8777 case command_FieldId_in: { // $comment
8778 *out_anon = false;
8779 } break;
8780 case command_FieldId_dot: { // $comment
8781 *out_anon = false;
8782 } break;
8783 case command_FieldId_xref: { // $comment
8784 *out_anon = false;
8785 retval=0;
8786 out_dflt="Y";
8787 } break;
8788 case command_FieldId_xns: { // bool: no argument required but value may be specified as xref:Y
8789 *out_anon = false;
8790 retval=0;
8791 out_dflt="Y";
8792 } break;
8793 case command_FieldId_noinput: { // bool: no argument required but value may be specified as xns:Y
8794 *out_anon = false;
8795 retval=0;
8796 out_dflt="Y";
8797 } break;
8798 case command_FieldId_check: { // bool: no argument required but value may be specified as noinput:Y
8799 *out_anon = false;
8800 retval=0;
8801 out_dflt="Y";
8802 } break;
8803 case command_FieldId_render: { // bool: no argument required but value may be specified as check:Y
8804 *out_anon = false;
8805 retval=0;
8806 out_dflt="Y";
8807 } break;
8808 default:
8809 retval=-1; // unrecognized
8810 }
8811 return retval;
8812}
8813
8814// --- command.amc_vis_proc.amc_vis.Start
8815// Start subprocess
8816// If subprocess already running, do nothing. Otherwise, start it
8817int command::amc_vis_Start(command::amc_vis_proc& parent) {
8818 int retval = 0;
8819 if (parent.pid == 0) {
8820 verblog(amc_vis_ToCmdline(parent)); // maybe print command
8821#ifdef WIN32
8822 algo_lib::ResolveExecFname(parent.path);
8823 tempstr cmdline(amc_vis_ToCmdline(parent));
8824 parent.pid = dospawn(Zeroterm(parent.path),Zeroterm(cmdline),parent.timeout,parent.fstdin,parent.fstdout,parent.fstderr);
8825#else
8826 parent.pid = fork();
8827 if (parent.pid == 0) { // child
8828 algo_lib::DieWithParent();
8829 if (parent.timeout > 0) {
8830 alarm(parent.timeout);
8831 }
8832 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstdin , 0);
8833 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstdout, 1);
8834 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstderr, 2);
8835 if (retval==0) retval= amc_vis_Execv(parent);
8836 if (retval != 0) { // if start fails, print error
8837 int err=errno;
8838 prerr("command.amc_vis_execv"
8839 <<Keyval("errno",err)
8840 <<Keyval("errstr",strerror(err))
8841 <<Keyval("comment","Execv failed"));
8842 }
8843 _exit(127); // if failed to start, exit anyway
8844 } else if (parent.pid == -1) {
8845 retval = errno; // failed to fork
8846 }
8847#endif
8848 }
8849 parent.status = parent.pid > 0 ? 0 : -1; // if didn't start, set error status
8850 return retval;
8851}
8852
8853// --- command.amc_vis_proc.amc_vis.StartRead
8854// Start subprocess & Read output
8855algo::Fildes command::amc_vis_StartRead(command::amc_vis_proc& parent, algo_lib::FFildes &read) {
8856 int pipefd[2];
8857 int rc=pipe(pipefd);
8858 (void)rc;
8859 read.fd.value = pipefd[0];
8860 parent.fstdout << ">&" << pipefd[1];
8861 amc_vis_Start(parent);
8862 (void)close(pipefd[1]);
8863 return read.fd;
8864}
8865
8866// --- command.amc_vis_proc.amc_vis.Kill
8867// Kill subprocess and wait
8868void command::amc_vis_Kill(command::amc_vis_proc& parent) {
8869 if (parent.pid != 0) {
8870 kill(parent.pid,9);
8871 amc_vis_Wait(parent);
8872 }
8873}
8874
8875// --- command.amc_vis_proc.amc_vis.Wait
8876// Wait for subprocess to return
8877void command::amc_vis_Wait(command::amc_vis_proc& parent) {
8878 if (parent.pid > 0) {
8879 int wait_flags = 0;
8880 int wait_status = 0;
8881 int rc = -1;
8882 do {
8883 // really wait for subprocess to exit
8884 rc = waitpid(parent.pid,&wait_status,wait_flags);
8885 } while (rc==-1 && errno==EINTR);
8886 if (rc == parent.pid) {
8887 parent.status = wait_status;
8888 parent.pid = 0;
8889 }
8890 }
8891}
8892
8893// --- command.amc_vis_proc.amc_vis.Exec
8894// Start + Wait
8895// Execute subprocess and return exit code
8896int command::amc_vis_Exec(command::amc_vis_proc& parent) {
8897 amc_vis_Start(parent);
8898 amc_vis_Wait(parent);
8899 return parent.status;
8900}
8901
8902// --- command.amc_vis_proc.amc_vis.ExecX
8903// Start + Wait, throw exception on error
8904// Execute subprocess; throw human-readable exception on error
8905void command::amc_vis_ExecX(command::amc_vis_proc& parent) {
8906 int rc = amc_vis_Exec(parent);
8907 vrfy(rc==0, tempstr() << "algo_lib.exec" << Keyval("cmd",amc_vis_ToCmdline(parent))
8908 << Keyval("comment",algo::DescribeWaitStatus(parent.status)));
8909}
8910
8911// --- command.amc_vis_proc.amc_vis.Execv
8912// Call execv()
8913// Call execv with specified parameters
8914int command::amc_vis_Execv(command::amc_vis_proc& parent) {
8915 int ret = 0;
8916 algo::StringAry args;
8917 amc_vis_ToArgv(parent, args);
8918 char **argv = (char**)alloca((ary_N(args)+1)*sizeof(*argv));
8919 ind_beg(algo::StringAry_ary_curs,arg,args) {
8920 argv[ind_curs(arg).index] = Zeroterm(arg);
8921 }ind_end;
8922 argv[ary_N(args)] = NULL;
8923 // if parent.path is relative, search for it in PATH
8924 algo_lib::ResolveExecFname(parent.path);
8925 ret = execv(Zeroterm(parent.path),argv);
8926 return ret;
8927}
8928
8929// --- command.amc_vis_proc.amc_vis.ToCmdline
8930algo::tempstr command::amc_vis_ToCmdline(command::amc_vis_proc& parent) {
8931 algo::tempstr retval;
8932 retval << parent.path << " ";
8933 command::amc_vis_PrintArgv(parent.cmd,retval);
8934 if (ch_N(parent.fstdin)) {
8935 retval << " " << parent.fstdin;
8936 }
8937 if (ch_N(parent.fstdout)) {
8938 retval << " " << parent.fstdout;
8939 }
8940 if (ch_N(parent.fstderr)) {
8941 retval << " 2" << parent.fstderr;
8942 }
8943 return retval;
8944}
8945
8946// --- command.amc_vis_proc.amc_vis.ToArgv
8947// Form array from the command line
8948void command::amc_vis_ToArgv(command::amc_vis_proc& parent, algo::StringAry& args) {
8949 ary_RemoveAll(args);
8950 ary_Alloc(args) << parent.path;
8951
8952 if (parent.cmd.ctype.expr != "%") {
8953 cstring *arg = &ary_Alloc(args);
8954 *arg << "-ctype:";
8955 command::ctype_Print(parent.cmd, *arg);
8956 }
8957
8958 if (parent.cmd.in != "data") {
8959 cstring *arg = &ary_Alloc(args);
8960 *arg << "-in:";
8961 cstring_Print(parent.cmd.in, *arg);
8962 }
8963
8964 if (parent.cmd.dot != "") {
8965 cstring *arg = &ary_Alloc(args);
8966 *arg << "-dot:";
8967 cstring_Print(parent.cmd.dot, *arg);
8968 }
8969
8970 if (parent.cmd.xref != false) {
8971 cstring *arg = &ary_Alloc(args);
8972 *arg << "-xref:";
8973 bool_Print(parent.cmd.xref, *arg);
8974 }
8975
8976 if (parent.cmd.xns != false) {
8977 cstring *arg = &ary_Alloc(args);
8978 *arg << "-xns:";
8979 bool_Print(parent.cmd.xns, *arg);
8980 }
8981
8982 if (parent.cmd.noinput != false) {
8983 cstring *arg = &ary_Alloc(args);
8984 *arg << "-noinput:";
8985 bool_Print(parent.cmd.noinput, *arg);
8986 }
8987
8988 if (parent.cmd.check != false) {
8989 cstring *arg = &ary_Alloc(args);
8990 *arg << "-check:";
8991 bool_Print(parent.cmd.check, *arg);
8992 }
8993
8994 if (parent.cmd.render != true) {
8995 cstring *arg = &ary_Alloc(args);
8996 *arg << "-render:";
8997 bool_Print(parent.cmd.render, *arg);
8998 }
8999 for (int i=1; i < algo_lib::_db.cmdline.verbose; ++i) {
9000 ary_Alloc(args) << "-verbose";
9001 }
9002}
9003
9004// --- command.amc_vis_proc..Uninit
9005void command::amc_vis_proc_Uninit(command::amc_vis_proc& parent) {
9006 command::amc_vis_proc &row = parent; (void)row;
9007
9008 // command.amc_vis_proc.amc_vis.Uninit (Exec) //
9009 amc_vis_Kill(parent); // kill child, ensure forward progress
9010}
9011
9012// --- command.ams_cat..ReadFieldMaybe
9013bool command::ams_cat_ReadFieldMaybe(command::ams_cat& parent, algo::strptr field, algo::strptr strval) {
9014 bool retval = true;
9015 command::FieldId field_id;
9016 (void)value_SetStrptrMaybe(field_id,field);
9017 switch(field_id) {
9018 case command_FieldId_in: {
9019 retval = algo::cstring_ReadStrptrMaybe(parent.in, strval);
9020 break;
9021 }
9022 default: break;
9023 }
9024 if (!retval) {
9025 algo_lib::AppendErrtext("attr",field);
9026 }
9027 return retval;
9028}
9029
9030// --- command.ams_cat..ReadTupleMaybe
9031// Read fields of command::ams_cat from attributes of ascii tuple TUPLE
9032bool command::ams_cat_ReadTupleMaybe(command::ams_cat &parent, algo::Tuple &tuple) {
9033 bool retval = true;
9034 ind_beg(algo::Tuple_attrs_curs,attr,tuple) {
9035 retval = ams_cat_ReadFieldMaybe(parent, attr.name, attr.value);
9036 if (!retval) {
9037 break;
9038 }
9039 }ind_end;
9040 return retval;
9041}
9042
9043// --- command.ams_cat..ToCmdline
9044// Convenience function that returns a full command line
9045// Assume command is in a directory called bin
9046tempstr command::ams_cat_ToCmdline(command::ams_cat& row) {
9047 tempstr ret;
9048 ret << "bin/ams_cat ";
9049 ams_cat_PrintArgv(row, ret);
9050 // inherit less intense verbose, debug options
9051 for (int i = 1; i < algo_lib::_db.cmdline.verbose; i++) {
9052 ret << " -verbose";
9053 }
9054 for (int i = 1; i < algo_lib::_db.cmdline.debug; i++) {
9055 ret << " -debug";
9056 }
9057 return ret;
9058}
9059
9060// --- command.ams_cat..PrintArgv
9061// print string representation of ROW to string STR
9062// cfmt:command.ams_cat.Argv printfmt:Tuple
9063void command::ams_cat_PrintArgv(command::ams_cat& row, algo::cstring& str) {
9064 algo::tempstr temp;
9065 (void)temp;
9066 (void)str;
9067 if (!(row.in == "data")) {
9068 ch_RemoveAll(temp);
9069 cstring_Print(row.in, temp);
9070 str << " -in:";
9071 strptr_PrintBash(temp,str);
9072 }
9073}
9074
9075// --- command.ams_cat..NArgs
9076// Used with command lines
9077// Return # of command-line arguments that must follow this argument
9078// If FIELD is invalid, return -1
9079i32 command::ams_cat_NArgs(command::FieldId field, algo::strptr& out_dflt, bool* out_anon) {
9080 i32 retval = 1;
9081 switch (field) {
9082 case command_FieldId_in: { // $comment
9083 *out_anon = false;
9084 } break;
9085 default:
9086 retval=-1; // unrecognized
9087 }
9088 (void)out_dflt;//only to avoid -Wunused-parameter
9089 return retval;
9090}
9091
9092// --- command.ams_cat_proc.ams_cat.Start
9093// Start subprocess
9094// If subprocess already running, do nothing. Otherwise, start it
9095int command::ams_cat_Start(command::ams_cat_proc& parent) {
9096 int retval = 0;
9097 if (parent.pid == 0) {
9098 verblog(ams_cat_ToCmdline(parent)); // maybe print command
9099#ifdef WIN32
9100 algo_lib::ResolveExecFname(parent.path);
9101 tempstr cmdline(ams_cat_ToCmdline(parent));
9102 parent.pid = dospawn(Zeroterm(parent.path),Zeroterm(cmdline),parent.timeout,parent.fstdin,parent.fstdout,parent.fstderr);
9103#else
9104 parent.pid = fork();
9105 if (parent.pid == 0) { // child
9106 algo_lib::DieWithParent();
9107 if (parent.timeout > 0) {
9108 alarm(parent.timeout);
9109 }
9110 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstdin , 0);
9111 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstdout, 1);
9112 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstderr, 2);
9113 if (retval==0) retval= ams_cat_Execv(parent);
9114 if (retval != 0) { // if start fails, print error
9115 int err=errno;
9116 prerr("command.ams_cat_execv"
9117 <<Keyval("errno",err)
9118 <<Keyval("errstr",strerror(err))
9119 <<Keyval("comment","Execv failed"));
9120 }
9121 _exit(127); // if failed to start, exit anyway
9122 } else if (parent.pid == -1) {
9123 retval = errno; // failed to fork
9124 }
9125#endif
9126 }
9127 parent.status = parent.pid > 0 ? 0 : -1; // if didn't start, set error status
9128 return retval;
9129}
9130
9131// --- command.ams_cat_proc.ams_cat.StartRead
9132// Start subprocess & Read output
9133algo::Fildes command::ams_cat_StartRead(command::ams_cat_proc& parent, algo_lib::FFildes &read) {
9134 int pipefd[2];
9135 int rc=pipe(pipefd);
9136 (void)rc;
9137 read.fd.value = pipefd[0];
9138 parent.fstdout << ">&" << pipefd[1];
9139 ams_cat_Start(parent);
9140 (void)close(pipefd[1]);
9141 return read.fd;
9142}
9143
9144// --- command.ams_cat_proc.ams_cat.Kill
9145// Kill subprocess and wait
9146void command::ams_cat_Kill(command::ams_cat_proc& parent) {
9147 if (parent.pid != 0) {
9148 kill(parent.pid,9);
9149 ams_cat_Wait(parent);
9150 }
9151}
9152
9153// --- command.ams_cat_proc.ams_cat.Wait
9154// Wait for subprocess to return
9155void command::ams_cat_Wait(command::ams_cat_proc& parent) {
9156 if (parent.pid > 0) {
9157 int wait_flags = 0;
9158 int wait_status = 0;
9159 int rc = -1;
9160 do {
9161 // really wait for subprocess to exit
9162 rc = waitpid(parent.pid,&wait_status,wait_flags);
9163 } while (rc==-1 && errno==EINTR);
9164 if (rc == parent.pid) {
9165 parent.status = wait_status;
9166 parent.pid = 0;
9167 }
9168 }
9169}
9170
9171// --- command.ams_cat_proc.ams_cat.Exec
9172// Start + Wait
9173// Execute subprocess and return exit code
9174int command::ams_cat_Exec(command::ams_cat_proc& parent) {
9175 ams_cat_Start(parent);
9176 ams_cat_Wait(parent);
9177 return parent.status;
9178}
9179
9180// --- command.ams_cat_proc.ams_cat.ExecX
9181// Start + Wait, throw exception on error
9182// Execute subprocess; throw human-readable exception on error
9183void command::ams_cat_ExecX(command::ams_cat_proc& parent) {
9184 int rc = ams_cat_Exec(parent);
9185 vrfy(rc==0, tempstr() << "algo_lib.exec" << Keyval("cmd",ams_cat_ToCmdline(parent))
9186 << Keyval("comment",algo::DescribeWaitStatus(parent.status)));
9187}
9188
9189// --- command.ams_cat_proc.ams_cat.Execv
9190// Call execv()
9191// Call execv with specified parameters
9192int command::ams_cat_Execv(command::ams_cat_proc& parent) {
9193 int ret = 0;
9194 algo::StringAry args;
9195 ams_cat_ToArgv(parent, args);
9196 char **argv = (char**)alloca((ary_N(args)+1)*sizeof(*argv));
9197 ind_beg(algo::StringAry_ary_curs,arg,args) {
9198 argv[ind_curs(arg).index] = Zeroterm(arg);
9199 }ind_end;
9200 argv[ary_N(args)] = NULL;
9201 // if parent.path is relative, search for it in PATH
9202 algo_lib::ResolveExecFname(parent.path);
9203 ret = execv(Zeroterm(parent.path),argv);
9204 return ret;
9205}
9206
9207// --- command.ams_cat_proc.ams_cat.ToCmdline
9208algo::tempstr command::ams_cat_ToCmdline(command::ams_cat_proc& parent) {
9209 algo::tempstr retval;
9210 retval << parent.path << " ";
9211 command::ams_cat_PrintArgv(parent.cmd,retval);
9212 if (ch_N(parent.fstdin)) {
9213 retval << " " << parent.fstdin;
9214 }
9215 if (ch_N(parent.fstdout)) {
9216 retval << " " << parent.fstdout;
9217 }
9218 if (ch_N(parent.fstderr)) {
9219 retval << " 2" << parent.fstderr;
9220 }
9221 return retval;
9222}
9223
9224// --- command.ams_cat_proc.ams_cat.ToArgv
9225// Form array from the command line
9226void command::ams_cat_ToArgv(command::ams_cat_proc& parent, algo::StringAry& args) {
9227 ary_RemoveAll(args);
9228 ary_Alloc(args) << parent.path;
9229
9230 if (parent.cmd.in != "data") {
9231 cstring *arg = &ary_Alloc(args);
9232 *arg << "-in:";
9233 cstring_Print(parent.cmd.in, *arg);
9234 }
9235 for (int i=1; i < algo_lib::_db.cmdline.verbose; ++i) {
9236 ary_Alloc(args) << "-verbose";
9237 }
9238}
9239
9240// --- command.ams_cat_proc..Uninit
9241void command::ams_cat_proc_Uninit(command::ams_cat_proc& parent) {
9242 command::ams_cat_proc &row = parent; (void)row;
9243
9244 // command.ams_cat_proc.ams_cat.Uninit (Exec) //
9245 ams_cat_Kill(parent); // kill child, ensure forward progress
9246}
9247
9248// --- command.ams_sendtest.trace.Print
9249// Print back to string
9250void command::trace_Print(command::ams_sendtest& parent, algo::cstring &out) {
9251 Regx_Print(parent.trace, out);
9252}
9253
9254// --- command.ams_sendtest.trace.ReadStrptrMaybe
9255// Read Regx from string
9256// Convert string to field. Return success value
9257bool command::trace_ReadStrptrMaybe(command::ams_sendtest& parent, algo::strptr in) {
9258 bool retval = true;
9259 Regx_ReadSql(parent.trace, in, true);
9260 return retval;
9261}
9262
9263// --- command.ams_sendtest..ReadFieldMaybe
9264bool command::ams_sendtest_ReadFieldMaybe(command::ams_sendtest& parent, algo::strptr field, algo::strptr strval) {
9265 bool retval = true;
9266 command::FieldId field_id;
9267 (void)value_SetStrptrMaybe(field_id,field);
9268 switch(field_id) {
9269 case command_FieldId_in: {
9270 retval = algo::cstring_ReadStrptrMaybe(parent.in, strval);
9271 break;
9272 }
9273 case command_FieldId_id: {
9274 retval = i32_ReadStrptrMaybe(parent.id, strval);
9275 break;
9276 }
9277 case command_FieldId_file_prefix: {
9278 retval = algo::cstring_ReadStrptrMaybe(parent.file_prefix, strval);
9279 break;
9280 }
9281 case command_FieldId_nchild: {
9282 retval = i32_ReadStrptrMaybe(parent.nchild, strval);
9283 break;
9284 }
9285 case command_FieldId_blocking: {
9286 retval = bool_ReadStrptrMaybe(parent.blocking, strval);
9287 break;
9288 }
9289 case command_FieldId_nmsg: {
9290 retval = i32_ReadStrptrMaybe(parent.nmsg, strval);
9291 break;
9292 }
9293 case command_FieldId_trace: {
9294 retval = trace_ReadStrptrMaybe(parent, strval);
9295 break;
9296 }
9297 case command_FieldId_timeout: {
9298 retval = i32_ReadStrptrMaybe(parent.timeout, strval);
9299 break;
9300 }
9301 case command_FieldId_recvdelay_ns: {
9302 retval = i64_ReadStrptrMaybe(parent.recvdelay_ns, strval);
9303 break;
9304 }
9305 case command_FieldId_senddelay_ns: {
9306 retval = i64_ReadStrptrMaybe(parent.senddelay_ns, strval);
9307 break;
9308 }
9309 case command_FieldId_msgsize_min: {
9310 retval = i32_ReadStrptrMaybe(parent.msgsize_min, strval);
9311 break;
9312 }
9313 case command_FieldId_msgsize_max: {
9314 retval = i32_ReadStrptrMaybe(parent.msgsize_max, strval);
9315 break;
9316 }
9317 case command_FieldId_bufsize: {
9318 retval = i32_ReadStrptrMaybe(parent.bufsize, strval);
9319 break;
9320 }
9321 case command_FieldId_recvdelay: {
9322 retval = i64_ReadStrptrMaybe(parent.recvdelay, strval);
9323 break;
9324 }
9325 default: break;
9326 }
9327 if (!retval) {
9328 algo_lib::AppendErrtext("attr",field);
9329 }
9330 return retval;
9331}
9332
9333// --- command.ams_sendtest..ReadTupleMaybe
9334// Read fields of command::ams_sendtest from attributes of ascii tuple TUPLE
9335bool command::ams_sendtest_ReadTupleMaybe(command::ams_sendtest &parent, algo::Tuple &tuple) {
9336 bool retval = true;
9337 ind_beg(algo::Tuple_attrs_curs,attr,tuple) {
9338 retval = ams_sendtest_ReadFieldMaybe(parent, attr.name, attr.value);
9339 if (!retval) {
9340 break;
9341 }
9342 }ind_end;
9343 return retval;
9344}
9345
9346// --- command.ams_sendtest..Init
9347// Set all fields to initial values.
9348void command::ams_sendtest_Init(command::ams_sendtest& parent) {
9349 parent.in = algo::strptr("data");
9350 parent.id = i32(0);
9351 parent.file_prefix = algo::strptr("");
9352 parent.nchild = i32(1);
9353 parent.blocking = bool(false);
9354 parent.nmsg = i32(1000);
9355 Regx_ReadSql(parent.trace, "", true);
9356 parent.timeout = i32(30);
9357 parent.recvdelay_ns = i64(0);
9358 parent.senddelay_ns = i64(0);
9359 parent.msgsize_min = i32(64);
9360 parent.msgsize_max = i32(1024);
9361 parent.bufsize = i32(32768);
9362 parent.recvdelay = i64(0);
9363}
9364
9365// --- command.ams_sendtest..ToCmdline
9366// Convenience function that returns a full command line
9367// Assume command is in a directory called bin
9368tempstr command::ams_sendtest_ToCmdline(command::ams_sendtest& row) {
9369 tempstr ret;
9370 ret << "bin/ams_sendtest ";
9371 ams_sendtest_PrintArgv(row, ret);
9372 // inherit less intense verbose, debug options
9373 for (int i = 1; i < algo_lib::_db.cmdline.verbose; i++) {
9374 ret << " -verbose";
9375 }
9376 for (int i = 1; i < algo_lib::_db.cmdline.debug; i++) {
9377 ret << " -debug";
9378 }
9379 return ret;
9380}
9381
9382// --- command.ams_sendtest..PrintArgv
9383// print string representation of ROW to string STR
9384// cfmt:command.ams_sendtest.Argv printfmt:Tuple
9385void command::ams_sendtest_PrintArgv(command::ams_sendtest& row, algo::cstring& str) {
9386 algo::tempstr temp;
9387 (void)temp;
9388 (void)str;
9389 if (!(row.in == "data")) {
9390 ch_RemoveAll(temp);
9391 cstring_Print(row.in, temp);
9392 str << " -in:";
9393 strptr_PrintBash(temp,str);
9394 }
9395 if (!(row.id == 0)) {
9396 ch_RemoveAll(temp);
9397 i32_Print(row.id, temp);
9398 str << " -id:";
9399 strptr_PrintBash(temp,str);
9400 }
9401 if (!(row.file_prefix == "")) {
9402 ch_RemoveAll(temp);
9403 cstring_Print(row.file_prefix, temp);
9404 str << " -file_prefix:";
9405 strptr_PrintBash(temp,str);
9406 }
9407 if (!(row.nchild == 1)) {
9408 ch_RemoveAll(temp);
9409 i32_Print(row.nchild, temp);
9410 str << " -nchild:";
9411 strptr_PrintBash(temp,str);
9412 }
9413 if (!(row.blocking == false)) {
9414 ch_RemoveAll(temp);
9415 bool_Print(row.blocking, temp);
9416 str << " -blocking:";
9417 strptr_PrintBash(temp,str);
9418 }
9419 if (!(row.nmsg == 1000)) {
9420 ch_RemoveAll(temp);
9421 i32_Print(row.nmsg, temp);
9422 str << " -nmsg:";
9423 strptr_PrintBash(temp,str);
9424 }
9425 if (!(row.trace.expr == "")) {
9426 ch_RemoveAll(temp);
9427 command::trace_Print(const_cast<command::ams_sendtest&>(row), temp);
9428 str << " -trace:";
9429 strptr_PrintBash(temp,str);
9430 }
9431 if (!(row.timeout == 30)) {
9432 ch_RemoveAll(temp);
9433 i32_Print(row.timeout, temp);
9434 str << " -timeout:";
9435 strptr_PrintBash(temp,str);
9436 }
9437 if (!(row.recvdelay_ns == 0)) {
9438 ch_RemoveAll(temp);
9439 i64_Print(row.recvdelay_ns, temp);
9440 str << " -recvdelay_ns:";
9441 strptr_PrintBash(temp,str);
9442 }
9443 if (!(row.senddelay_ns == 0)) {
9444 ch_RemoveAll(temp);
9445 i64_Print(row.senddelay_ns, temp);
9446 str << " -senddelay_ns:";
9447 strptr_PrintBash(temp,str);
9448 }
9449 if (!(row.msgsize_min == 64)) {
9450 ch_RemoveAll(temp);
9451 i32_Print(row.msgsize_min, temp);
9452 str << " -msgsize_min:";
9453 strptr_PrintBash(temp,str);
9454 }
9455 if (!(row.msgsize_max == 1024)) {
9456 ch_RemoveAll(temp);
9457 i32_Print(row.msgsize_max, temp);
9458 str << " -msgsize_max:";
9459 strptr_PrintBash(temp,str);
9460 }
9461 if (!(row.bufsize == 32768)) {
9462 ch_RemoveAll(temp);
9463 i32_Print(row.bufsize, temp);
9464 str << " -bufsize:";
9465 strptr_PrintBash(temp,str);
9466 }
9467 if (!(row.recvdelay == 0)) {
9468 ch_RemoveAll(temp);
9469 i64_Print(row.recvdelay, temp);
9470 str << " -recvdelay:";
9471 strptr_PrintBash(temp,str);
9472 }
9473}
9474
9475// --- command.ams_sendtest..NArgs
9476// Used with command lines
9477// Return # of command-line arguments that must follow this argument
9478// If FIELD is invalid, return -1
9479i32 command::ams_sendtest_NArgs(command::FieldId field, algo::strptr& out_dflt, bool* out_anon) {
9480 i32 retval = 1;
9481 switch (field) {
9482 case command_FieldId_in: { // $comment
9483 *out_anon = false;
9484 } break;
9485 case command_FieldId_id: { // $comment
9486 *out_anon = false;
9487 } break;
9488 case command_FieldId_file_prefix: { // $comment
9489 *out_anon = false;
9490 } break;
9491 case command_FieldId_nchild: { // $comment
9492 *out_anon = false;
9493 } break;
9494 case command_FieldId_blocking: { // $comment
9495 *out_anon = false;
9496 retval=0;
9497 out_dflt="Y";
9498 } break;
9499 case command_FieldId_nmsg: { // bool: no argument required but value may be specified as blocking:Y
9500 *out_anon = false;
9501 } break;
9502 case command_FieldId_trace: { // bool: no argument required but value may be specified as blocking:Y
9503 *out_anon = false;
9504 } break;
9505 case command_FieldId_timeout: { // bool: no argument required but value may be specified as blocking:Y
9506 *out_anon = false;
9507 } break;
9508 case command_FieldId_recvdelay_ns: { // bool: no argument required but value may be specified as blocking:Y
9509 *out_anon = false;
9510 } break;
9511 case command_FieldId_senddelay_ns: { // bool: no argument required but value may be specified as blocking:Y
9512 *out_anon = false;
9513 } break;
9514 case command_FieldId_msgsize_min: { // bool: no argument required but value may be specified as blocking:Y
9515 *out_anon = false;
9516 } break;
9517 case command_FieldId_msgsize_max: { // bool: no argument required but value may be specified as blocking:Y
9518 *out_anon = false;
9519 } break;
9520 case command_FieldId_bufsize: { // bool: no argument required but value may be specified as blocking:Y
9521 *out_anon = false;
9522 } break;
9523 case command_FieldId_recvdelay: { // bool: no argument required but value may be specified as blocking:Y
9524 *out_anon = false;
9525 } break;
9526 default:
9527 retval=-1; // unrecognized
9528 }
9529 return retval;
9530}
9531
9532// --- command.ams_sendtest_proc.ams_sendtest.Start
9533// Start subprocess
9534// If subprocess already running, do nothing. Otherwise, start it
9535int command::ams_sendtest_Start(command::ams_sendtest_proc& parent) {
9536 int retval = 0;
9537 if (parent.pid == 0) {
9538 verblog(ams_sendtest_ToCmdline(parent)); // maybe print command
9539#ifdef WIN32
9540 algo_lib::ResolveExecFname(parent.path);
9541 tempstr cmdline(ams_sendtest_ToCmdline(parent));
9542 parent.pid = dospawn(Zeroterm(parent.path),Zeroterm(cmdline),parent.timeout,parent.fstdin,parent.fstdout,parent.fstderr);
9543#else
9544 parent.pid = fork();
9545 if (parent.pid == 0) { // child
9546 algo_lib::DieWithParent();
9547 if (parent.timeout > 0) {
9548 alarm(parent.timeout);
9549 }
9550 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstdin , 0);
9551 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstdout, 1);
9552 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstderr, 2);
9553 if (retval==0) retval= ams_sendtest_Execv(parent);
9554 if (retval != 0) { // if start fails, print error
9555 int err=errno;
9556 prerr("command.ams_sendtest_execv"
9557 <<Keyval("errno",err)
9558 <<Keyval("errstr",strerror(err))
9559 <<Keyval("comment","Execv failed"));
9560 }
9561 _exit(127); // if failed to start, exit anyway
9562 } else if (parent.pid == -1) {
9563 retval = errno; // failed to fork
9564 }
9565#endif
9566 }
9567 parent.status = parent.pid > 0 ? 0 : -1; // if didn't start, set error status
9568 return retval;
9569}
9570
9571// --- command.ams_sendtest_proc.ams_sendtest.StartRead
9572// Start subprocess & Read output
9573algo::Fildes command::ams_sendtest_StartRead(command::ams_sendtest_proc& parent, algo_lib::FFildes &read) {
9574 int pipefd[2];
9575 int rc=pipe(pipefd);
9576 (void)rc;
9577 read.fd.value = pipefd[0];
9578 parent.fstdout << ">&" << pipefd[1];
9579 ams_sendtest_Start(parent);
9580 (void)close(pipefd[1]);
9581 return read.fd;
9582}
9583
9584// --- command.ams_sendtest_proc.ams_sendtest.Kill
9585// Kill subprocess and wait
9586void command::ams_sendtest_Kill(command::ams_sendtest_proc& parent) {
9587 if (parent.pid != 0) {
9588 kill(parent.pid,9);
9589 ams_sendtest_Wait(parent);
9590 }
9591}
9592
9593// --- command.ams_sendtest_proc.ams_sendtest.Wait
9594// Wait for subprocess to return
9595void command::ams_sendtest_Wait(command::ams_sendtest_proc& parent) {
9596 if (parent.pid > 0) {
9597 int wait_flags = 0;
9598 int wait_status = 0;
9599 int rc = -1;
9600 do {
9601 // really wait for subprocess to exit
9602 rc = waitpid(parent.pid,&wait_status,wait_flags);
9603 } while (rc==-1 && errno==EINTR);
9604 if (rc == parent.pid) {
9605 parent.status = wait_status;
9606 parent.pid = 0;
9607 }
9608 }
9609}
9610
9611// --- command.ams_sendtest_proc.ams_sendtest.Exec
9612// Start + Wait
9613// Execute subprocess and return exit code
9614int command::ams_sendtest_Exec(command::ams_sendtest_proc& parent) {
9615 ams_sendtest_Start(parent);
9616 ams_sendtest_Wait(parent);
9617 return parent.status;
9618}
9619
9620// --- command.ams_sendtest_proc.ams_sendtest.ExecX
9621// Start + Wait, throw exception on error
9622// Execute subprocess; throw human-readable exception on error
9623void command::ams_sendtest_ExecX(command::ams_sendtest_proc& parent) {
9624 int rc = ams_sendtest_Exec(parent);
9625 vrfy(rc==0, tempstr() << "algo_lib.exec" << Keyval("cmd",ams_sendtest_ToCmdline(parent))
9626 << Keyval("comment",algo::DescribeWaitStatus(parent.status)));
9627}
9628
9629// --- command.ams_sendtest_proc.ams_sendtest.Execv
9630// Call execv()
9631// Call execv with specified parameters
9632int command::ams_sendtest_Execv(command::ams_sendtest_proc& parent) {
9633 int ret = 0;
9634 algo::StringAry args;
9635 ams_sendtest_ToArgv(parent, args);
9636 char **argv = (char**)alloca((ary_N(args)+1)*sizeof(*argv));
9637 ind_beg(algo::StringAry_ary_curs,arg,args) {
9638 argv[ind_curs(arg).index] = Zeroterm(arg);
9639 }ind_end;
9640 argv[ary_N(args)] = NULL;
9641 // if parent.path is relative, search for it in PATH
9642 algo_lib::ResolveExecFname(parent.path);
9643 ret = execv(Zeroterm(parent.path),argv);
9644 return ret;
9645}
9646
9647// --- command.ams_sendtest_proc.ams_sendtest.ToCmdline
9648algo::tempstr command::ams_sendtest_ToCmdline(command::ams_sendtest_proc& parent) {
9649 algo::tempstr retval;
9650 retval << parent.path << " ";
9651 command::ams_sendtest_PrintArgv(parent.cmd,retval);
9652 if (ch_N(parent.fstdin)) {
9653 retval << " " << parent.fstdin;
9654 }
9655 if (ch_N(parent.fstdout)) {
9656 retval << " " << parent.fstdout;
9657 }
9658 if (ch_N(parent.fstderr)) {
9659 retval << " 2" << parent.fstderr;
9660 }
9661 return retval;
9662}
9663
9664// --- command.ams_sendtest_proc.ams_sendtest.ToArgv
9665// Form array from the command line
9666void command::ams_sendtest_ToArgv(command::ams_sendtest_proc& parent, algo::StringAry& args) {
9667 ary_RemoveAll(args);
9668 ary_Alloc(args) << parent.path;
9669
9670 if (parent.cmd.in != "data") {
9671 cstring *arg = &ary_Alloc(args);
9672 *arg << "-in:";
9673 cstring_Print(parent.cmd.in, *arg);
9674 }
9675
9676 if (parent.cmd.id != 0) {
9677 cstring *arg = &ary_Alloc(args);
9678 *arg << "-id:";
9679 i32_Print(parent.cmd.id, *arg);
9680 }
9681
9682 if (parent.cmd.file_prefix != "") {
9683 cstring *arg = &ary_Alloc(args);
9684 *arg << "-file_prefix:";
9685 cstring_Print(parent.cmd.file_prefix, *arg);
9686 }
9687
9688 if (parent.cmd.nchild != 1) {
9689 cstring *arg = &ary_Alloc(args);
9690 *arg << "-nchild:";
9691 i32_Print(parent.cmd.nchild, *arg);
9692 }
9693
9694 if (parent.cmd.blocking != false) {
9695 cstring *arg = &ary_Alloc(args);
9696 *arg << "-blocking:";
9697 bool_Print(parent.cmd.blocking, *arg);
9698 }
9699
9700 if (parent.cmd.nmsg != 1000) {
9701 cstring *arg = &ary_Alloc(args);
9702 *arg << "-nmsg:";
9703 i32_Print(parent.cmd.nmsg, *arg);
9704 }
9705
9706 if (parent.cmd.trace.expr != "") {
9707 cstring *arg = &ary_Alloc(args);
9708 *arg << "-trace:";
9709 command::trace_Print(parent.cmd, *arg);
9710 }
9711
9712 if (parent.cmd.timeout != 30) {
9713 cstring *arg = &ary_Alloc(args);
9714 *arg << "-timeout:";
9715 i32_Print(parent.cmd.timeout, *arg);
9716 }
9717
9718 if (parent.cmd.recvdelay_ns != 0) {
9719 cstring *arg = &ary_Alloc(args);
9720 *arg << "-recvdelay_ns:";
9721 i64_Print(parent.cmd.recvdelay_ns, *arg);
9722 }
9723
9724 if (parent.cmd.senddelay_ns != 0) {
9725 cstring *arg = &ary_Alloc(args);
9726 *arg << "-senddelay_ns:";
9727 i64_Print(parent.cmd.senddelay_ns, *arg);
9728 }
9729
9730 if (parent.cmd.msgsize_min != 64) {
9731 cstring *arg = &ary_Alloc(args);
9732 *arg << "-msgsize_min:";
9733 i32_Print(parent.cmd.msgsize_min, *arg);
9734 }
9735
9736 if (parent.cmd.msgsize_max != 1024) {
9737 cstring *arg = &ary_Alloc(args);
9738 *arg << "-msgsize_max:";
9739 i32_Print(parent.cmd.msgsize_max, *arg);
9740 }
9741
9742 if (parent.cmd.bufsize != 32768) {
9743 cstring *arg = &ary_Alloc(args);
9744 *arg << "-bufsize:";
9745 i32_Print(parent.cmd.bufsize, *arg);
9746 }
9747
9748 if (parent.cmd.recvdelay != 0) {
9749 cstring *arg = &ary_Alloc(args);
9750 *arg << "-recvdelay:";
9751 i64_Print(parent.cmd.recvdelay, *arg);
9752 }
9753 for (int i=1; i < algo_lib::_db.cmdline.verbose; ++i) {
9754 ary_Alloc(args) << "-verbose";
9755 }
9756}
9757
9758// --- command.ams_sendtest_proc..Uninit
9759void command::ams_sendtest_proc_Uninit(command::ams_sendtest_proc& parent) {
9760 command::ams_sendtest_proc &row = parent; (void)row;
9761
9762 // command.ams_sendtest_proc.ams_sendtest.Uninit (Exec) //
9763 ams_sendtest_Kill(parent); // kill child, ensure forward progress
9764}
9765
9766// --- command.apm.package.Print
9767// Print back to string
9768void command::package_Print(command::apm& parent, algo::cstring &out) {
9769 Regx_Print(parent.package, out);
9770}
9771
9772// --- command.apm.package.ReadStrptrMaybe
9773// Read Regx from string
9774// Convert string to field. Return success value
9775bool command::package_ReadStrptrMaybe(command::apm& parent, algo::strptr in) {
9776 bool retval = true;
9777 Regx_ReadSql(parent.package, in, true);
9778 return retval;
9779}
9780
9781// --- command.apm.ns.Print
9782// Print back to string
9783void command::ns_Print(command::apm& parent, algo::cstring &out) {
9784 Regx_Print(parent.ns, out);
9785}
9786
9787// --- command.apm.ns.ReadStrptrMaybe
9788// Read Regx from string
9789// Convert string to field. Return success value
9790bool command::ns_ReadStrptrMaybe(command::apm& parent, algo::strptr in) {
9791 bool retval = true;
9792 Regx_ReadSql(parent.ns, in, true);
9793 return retval;
9794}
9795
9796// --- command.apm..ReadFieldMaybe
9797bool command::apm_ReadFieldMaybe(command::apm& parent, algo::strptr field, algo::strptr strval) {
9798 bool retval = true;
9799 command::FieldId field_id;
9800 (void)value_SetStrptrMaybe(field_id,field);
9801 switch(field_id) {
9802 case command_FieldId_in: {
9803 retval = algo::cstring_ReadStrptrMaybe(parent.in, strval);
9804 break;
9805 }
9806 case command_FieldId_pkgdata: {
9807 retval = algo::cstring_ReadStrptrMaybe(parent.pkgdata, strval);
9808 break;
9809 }
9810 case command_FieldId_package: {
9811 retval = package_ReadStrptrMaybe(parent, strval);
9812 break;
9813 }
9814 case command_FieldId_ns: {
9815 retval = ns_ReadStrptrMaybe(parent, strval);
9816 break;
9817 }
9818 case command_FieldId_install: {
9819 retval = bool_ReadStrptrMaybe(parent.install, strval);
9820 break;
9821 }
9822 case command_FieldId_update: {
9823 retval = bool_ReadStrptrMaybe(parent.update, strval);
9824 break;
9825 }
9826 case command_FieldId_list: {
9827 retval = bool_ReadStrptrMaybe(parent.list, strval);
9828 break;
9829 }
9830 case command_FieldId_diff: {
9831 retval = bool_ReadStrptrMaybe(parent.diff, strval);
9832 break;
9833 }
9834 case command_FieldId_push: {
9835 retval = bool_ReadStrptrMaybe(parent.push, strval);
9836 break;
9837 }
9838 case command_FieldId_check: {
9839 retval = bool_ReadStrptrMaybe(parent.check, strval);
9840 break;
9841 }
9842 case command_FieldId_remove: {
9843 retval = bool_ReadStrptrMaybe(parent.remove, strval);
9844 break;
9845 }
9846 case command_FieldId_origin: {
9847 retval = algo::Smallstr200_ReadStrptrMaybe(parent.origin, strval);
9848 break;
9849 }
9850 case command_FieldId_ref: {
9851 retval = algo::Smallstr50_ReadStrptrMaybe(parent.ref, strval);
9852 break;
9853 }
9854 case command_FieldId_dry_run: {
9855 retval = bool_ReadStrptrMaybe(parent.dry_run, strval);
9856 break;
9857 }
9858 case command_FieldId_showrec: {
9859 retval = bool_ReadStrptrMaybe(parent.showrec, strval);
9860 break;
9861 }
9862 case command_FieldId_showfile: {
9863 retval = bool_ReadStrptrMaybe(parent.showfile, strval);
9864 break;
9865 }
9866 case command_FieldId_R: {
9867 retval = bool_ReadStrptrMaybe(parent.R, strval);
9868 break;
9869 }
9870 case command_FieldId_l: {
9871 retval = bool_ReadStrptrMaybe(parent.l, strval);
9872 break;
9873 }
9874 case command_FieldId_reset: {
9875 retval = bool_ReadStrptrMaybe(parent.reset, strval);
9876 break;
9877 }
9878 case command_FieldId_checkclean: {
9879 retval = bool_ReadStrptrMaybe(parent.checkclean, strval);
9880 break;
9881 }
9882 case command_FieldId_t: {
9883 retval = bool_ReadStrptrMaybe(parent.t, strval);
9884 break;
9885 }
9886 case command_FieldId_stat: {
9887 retval = bool_ReadStrptrMaybe(parent.stat, strval);
9888 break;
9889 }
9890 case command_FieldId_annotate: {
9891 retval = algo::cstring_ReadStrptrMaybe(parent.annotate, strval);
9892 break;
9893 }
9894 case command_FieldId_data_in: {
9895 retval = algo::cstring_ReadStrptrMaybe(parent.data_in, strval);
9896 break;
9897 }
9898 case command_FieldId_e: {
9899 retval = bool_ReadStrptrMaybe(parent.e, strval);
9900 break;
9901 }
9902 case command_FieldId_binpath: {
9903 retval = algo::cstring_ReadStrptrMaybe(parent.binpath, strval);
9904 break;
9905 }
9906 default: break;
9907 }
9908 if (!retval) {
9909 algo_lib::AppendErrtext("attr",field);
9910 }
9911 return retval;
9912}
9913
9914// --- command.apm..ReadTupleMaybe
9915// Read fields of command::apm from attributes of ascii tuple TUPLE
9916bool command::apm_ReadTupleMaybe(command::apm &parent, algo::Tuple &tuple) {
9917 bool retval = true;
9918 int anon_idx = 0;
9919 ind_beg(algo::Tuple_attrs_curs,attr,tuple) {
9920 if (ch_N(attr.name) == 0) {
9921 attr.name = apm_GetAnon(parent, anon_idx++);
9922 }
9923 retval = apm_ReadFieldMaybe(parent, attr.name, attr.value);
9924 if (!retval) {
9925 break;
9926 }
9927 }ind_end;
9928 return retval;
9929}
9930
9931// --- command.apm..Init
9932// Set all fields to initial values.
9933void command::apm_Init(command::apm& parent) {
9934 parent.in = algo::strptr("data");
9935 parent.pkgdata = algo::strptr("");
9936 Regx_ReadSql(parent.package, "", true);
9937 Regx_ReadSql(parent.ns, "", true);
9938 parent.install = bool(false);
9939 parent.update = bool(false);
9940 parent.list = bool(false);
9941 parent.diff = bool(false);
9942 parent.push = bool(false);
9943 parent.check = bool(false);
9944 parent.remove = bool(false);
9945 parent.origin = algo::strptr("");
9946 parent.ref = algo::strptr("");
9947 parent.dry_run = bool(false);
9948 parent.showrec = bool(false);
9949 parent.showfile = bool(false);
9950 parent.R = bool(false);
9951 parent.l = bool(false);
9952 parent.reset = bool(false);
9953 parent.checkclean = bool(true);
9954 parent.t = bool(false);
9955 parent.stat = bool(false);
9956 parent.annotate = algo::strptr("");
9957 parent.data_in = algo::strptr("data");
9958 parent.e = bool(false);
9959 parent.binpath = algo::strptr("bin");
9960}
9961
9962// --- command.apm..ToCmdline
9963// Convenience function that returns a full command line
9964// Assume command is in a directory called bin
9965tempstr command::apm_ToCmdline(command::apm& row) {
9966 tempstr ret;
9967 ret << "bin/apm ";
9968 apm_PrintArgv(row, ret);
9969 // inherit less intense verbose, debug options
9970 for (int i = 1; i < algo_lib::_db.cmdline.verbose; i++) {
9971 ret << " -verbose";
9972 }
9973 for (int i = 1; i < algo_lib::_db.cmdline.debug; i++) {
9974 ret << " -debug";
9975 }
9976 return ret;
9977}
9978
9979// --- command.apm..PrintArgv
9980// print string representation of ROW to string STR
9981// cfmt:command.apm.Argv printfmt:Tuple
9982void command::apm_PrintArgv(command::apm& row, algo::cstring& str) {
9983 algo::tempstr temp;
9984 (void)temp;
9985 (void)str;
9986 if (!(row.in == "data")) {
9987 ch_RemoveAll(temp);
9988 cstring_Print(row.in, temp);
9989 str << " -in:";
9990 strptr_PrintBash(temp,str);
9991 }
9992 if (!(row.pkgdata == "")) {
9993 ch_RemoveAll(temp);
9994 cstring_Print(row.pkgdata, temp);
9995 str << " -pkgdata:";
9996 strptr_PrintBash(temp,str);
9997 }
9998 ch_RemoveAll(temp);
9999 command::package_Print(const_cast<command::apm&>(row), temp);
10000 str << " -package:";
10001 strptr_PrintBash(temp,str);
10002 if (!(row.ns.expr == "")) {
10003 ch_RemoveAll(temp);
10004 command::ns_Print(const_cast<command::apm&>(row), temp);
10005 str << " -ns:";
10006 strptr_PrintBash(temp,str);
10007 }
10008 if (!(row.install == false)) {
10009 ch_RemoveAll(temp);
10010 bool_Print(row.install, temp);
10011 str << " -install:";
10012 strptr_PrintBash(temp,str);
10013 }
10014 if (!(row.update == false)) {
10015 ch_RemoveAll(temp);
10016 bool_Print(row.update, temp);
10017 str << " -update:";
10018 strptr_PrintBash(temp,str);
10019 }
10020 if (!(row.list == false)) {
10021 ch_RemoveAll(temp);
10022 bool_Print(row.list, temp);
10023 str << " -list:";
10024 strptr_PrintBash(temp,str);
10025 }
10026 if (!(row.diff == false)) {
10027 ch_RemoveAll(temp);
10028 bool_Print(row.diff, temp);
10029 str << " -diff:";
10030 strptr_PrintBash(temp,str);
10031 }
10032 if (!(row.push == false)) {
10033 ch_RemoveAll(temp);
10034 bool_Print(row.push, temp);
10035 str << " -push:";
10036 strptr_PrintBash(temp,str);
10037 }
10038 if (!(row.check == false)) {
10039 ch_RemoveAll(temp);
10040 bool_Print(row.check, temp);
10041 str << " -check:";
10042 strptr_PrintBash(temp,str);
10043 }
10044 if (!(row.remove == false)) {
10045 ch_RemoveAll(temp);
10046 bool_Print(row.remove, temp);
10047 str << " -remove:";
10048 strptr_PrintBash(temp,str);
10049 }
10050 if (!(row.origin == "")) {
10051 ch_RemoveAll(temp);
10052 Smallstr200_Print(row.origin, temp);
10053 str << " -origin:";
10054 strptr_PrintBash(temp,str);
10055 }
10056 if (!(row.ref == "")) {
10057 ch_RemoveAll(temp);
10058 Smallstr50_Print(row.ref, temp);
10059 str << " -ref:";
10060 strptr_PrintBash(temp,str);
10061 }
10062 if (!(row.dry_run == false)) {
10063 ch_RemoveAll(temp);
10064 bool_Print(row.dry_run, temp);
10065 str << " -dry_run:";
10066 strptr_PrintBash(temp,str);
10067 }
10068 if (!(row.showrec == false)) {
10069 ch_RemoveAll(temp);
10070 bool_Print(row.showrec, temp);
10071 str << " -showrec:";
10072 strptr_PrintBash(temp,str);
10073 }
10074 if (!(row.showfile == false)) {
10075 ch_RemoveAll(temp);
10076 bool_Print(row.showfile, temp);
10077 str << " -showfile:";
10078 strptr_PrintBash(temp,str);
10079 }
10080 if (!(row.R == false)) {
10081 ch_RemoveAll(temp);
10082 bool_Print(row.R, temp);
10083 str << " -R:";
10084 strptr_PrintBash(temp,str);
10085 }
10086 if (!(row.l == false)) {
10087 ch_RemoveAll(temp);
10088 bool_Print(row.l, temp);
10089 str << " -l:";
10090 strptr_PrintBash(temp,str);
10091 }
10092 if (!(row.reset == false)) {
10093 ch_RemoveAll(temp);
10094 bool_Print(row.reset, temp);
10095 str << " -reset:";
10096 strptr_PrintBash(temp,str);
10097 }
10098 if (!(row.checkclean == true)) {
10099 ch_RemoveAll(temp);
10100 bool_Print(row.checkclean, temp);
10101 str << " -checkclean:";
10102 strptr_PrintBash(temp,str);
10103 }
10104 if (!(row.t == false)) {
10105 ch_RemoveAll(temp);
10106 bool_Print(row.t, temp);
10107 str << " -t:";
10108 strptr_PrintBash(temp,str);
10109 }
10110 if (!(row.stat == false)) {
10111 ch_RemoveAll(temp);
10112 bool_Print(row.stat, temp);
10113 str << " -stat:";
10114 strptr_PrintBash(temp,str);
10115 }
10116 if (!(row.annotate == "")) {
10117 ch_RemoveAll(temp);
10118 cstring_Print(row.annotate, temp);
10119 str << " -annotate:";
10120 strptr_PrintBash(temp,str);
10121 }
10122 if (!(row.data_in == "data")) {
10123 ch_RemoveAll(temp);
10124 cstring_Print(row.data_in, temp);
10125 str << " -data_in:";
10126 strptr_PrintBash(temp,str);
10127 }
10128 if (!(row.e == false)) {
10129 ch_RemoveAll(temp);
10130 bool_Print(row.e, temp);
10131 str << " -e:";
10132 strptr_PrintBash(temp,str);
10133 }
10134 if (!(row.binpath == "bin")) {
10135 ch_RemoveAll(temp);
10136 cstring_Print(row.binpath, temp);
10137 str << " -binpath:";
10138 strptr_PrintBash(temp,str);
10139 }
10140}
10141
10142// --- command.apm..GetAnon
10143algo::strptr command::apm_GetAnon(command::apm &parent, i32 idx) {
10144 (void)parent;//only to avoid -Wunused-parameter
10145 switch(idx) {
10146 case(0): return strptr("package", 7);
10147 default: return algo::strptr();
10148 }
10149}
10150
10151// --- command.apm..NArgs
10152// Used with command lines
10153// Return # of command-line arguments that must follow this argument
10154// If FIELD is invalid, return -1
10155i32 command::apm_NArgs(command::FieldId field, algo::strptr& out_dflt, bool* out_anon) {
10156 i32 retval = 1;
10157 switch (field) {
10158 case command_FieldId_in: { // $comment
10159 *out_anon = false;
10160 } break;
10161 case command_FieldId_pkgdata: { // $comment
10162 *out_anon = false;
10163 } break;
10164 case command_FieldId_package: { // $comment
10165 *out_anon = true;
10166 } break;
10167 case command_FieldId_ns: { // $comment
10168 *out_anon = false;
10169 } break;
10170 case command_FieldId_install: { // $comment
10171 *out_anon = false;
10172 retval=0;
10173 out_dflt="Y";
10174 } break;
10175 case command_FieldId_update: { // bool: no argument required but value may be specified as install:Y
10176 *out_anon = false;
10177 retval=0;
10178 out_dflt="Y";
10179 } break;
10180 case command_FieldId_list: { // bool: no argument required but value may be specified as update:Y
10181 *out_anon = false;
10182 retval=0;
10183 out_dflt="Y";
10184 } break;
10185 case command_FieldId_diff: { // bool: no argument required but value may be specified as list:Y
10186 *out_anon = false;
10187 retval=0;
10188 out_dflt="Y";
10189 } break;
10190 case command_FieldId_push: { // bool: no argument required but value may be specified as diff:Y
10191 *out_anon = false;
10192 retval=0;
10193 out_dflt="Y";
10194 } break;
10195 case command_FieldId_check: { // bool: no argument required but value may be specified as push:Y
10196 *out_anon = false;
10197 retval=0;
10198 out_dflt="Y";
10199 } break;
10200 case command_FieldId_remove: { // bool: no argument required but value may be specified as check:Y
10201 *out_anon = false;
10202 retval=0;
10203 out_dflt="Y";
10204 } break;
10205 case command_FieldId_origin: { // bool: no argument required but value may be specified as remove:Y
10206 *out_anon = false;
10207 } break;
10208 case command_FieldId_ref: { // bool: no argument required but value may be specified as remove:Y
10209 *out_anon = false;
10210 } break;
10211 case command_FieldId_dry_run: { // bool: no argument required but value may be specified as remove:Y
10212 *out_anon = false;
10213 retval=0;
10214 out_dflt="Y";
10215 } break;
10216 case command_FieldId_showrec: { // bool: no argument required but value may be specified as dry_run:Y
10217 *out_anon = false;
10218 retval=0;
10219 out_dflt="Y";
10220 } break;
10221 case command_FieldId_showfile: { // bool: no argument required but value may be specified as showrec:Y
10222 *out_anon = false;
10223 retval=0;
10224 out_dflt="Y";
10225 } break;
10226 case command_FieldId_R: { // bool: no argument required but value may be specified as showfile:Y
10227 *out_anon = false;
10228 retval=0;
10229 out_dflt="Y";
10230 } break;
10231 case command_FieldId_l: { // bool: no argument required but value may be specified as R:Y
10232 *out_anon = false;
10233 retval=0;
10234 out_dflt="Y";
10235 } break;
10236 case command_FieldId_reset: { // bool: no argument required but value may be specified as l:Y
10237 *out_anon = false;
10238 retval=0;
10239 out_dflt="Y";
10240 } break;
10241 case command_FieldId_checkclean: { // bool: no argument required but value may be specified as reset:Y
10242 *out_anon = false;
10243 retval=0;
10244 out_dflt="Y";
10245 } break;
10246 case command_FieldId_t: { // bool: no argument required but value may be specified as checkclean:Y
10247 *out_anon = false;
10248 retval=0;
10249 out_dflt="Y";
10250 } break;
10251 case command_FieldId_stat: { // bool: no argument required but value may be specified as t:Y
10252 *out_anon = false;
10253 retval=0;
10254 out_dflt="Y";
10255 } break;
10256 case command_FieldId_annotate: { // bool: no argument required but value may be specified as stat:Y
10257 *out_anon = false;
10258 } break;
10259 case command_FieldId_data_in: { // bool: no argument required but value may be specified as stat:Y
10260 *out_anon = false;
10261 } break;
10262 case command_FieldId_e: { // bool: no argument required but value may be specified as stat:Y
10263 *out_anon = false;
10264 retval=0;
10265 out_dflt="Y";
10266 } break;
10267 case command_FieldId_binpath: { // bool: no argument required but value may be specified as e:Y
10268 *out_anon = false;
10269 } break;
10270 default:
10271 retval=-1; // unrecognized
10272 }
10273 return retval;
10274}
10275
10276// --- command.apm_proc.apm.Start
10277// Start subprocess
10278// If subprocess already running, do nothing. Otherwise, start it
10279int command::apm_Start(command::apm_proc& parent) {
10280 int retval = 0;
10281 if (parent.pid == 0) {
10282 verblog(apm_ToCmdline(parent)); // maybe print command
10283#ifdef WIN32
10284 algo_lib::ResolveExecFname(parent.path);
10285 tempstr cmdline(apm_ToCmdline(parent));
10286 parent.pid = dospawn(Zeroterm(parent.path),Zeroterm(cmdline),parent.timeout,parent.fstdin,parent.fstdout,parent.fstderr);
10287#else
10288 parent.pid = fork();
10289 if (parent.pid == 0) { // child
10290 algo_lib::DieWithParent();
10291 if (parent.timeout > 0) {
10292 alarm(parent.timeout);
10293 }
10294 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstdin , 0);
10295 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstdout, 1);
10296 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstderr, 2);
10297 if (retval==0) retval= apm_Execv(parent);
10298 if (retval != 0) { // if start fails, print error
10299 int err=errno;
10300 prerr("command.apm_execv"
10301 <<Keyval("errno",err)
10302 <<Keyval("errstr",strerror(err))
10303 <<Keyval("comment","Execv failed"));
10304 }
10305 _exit(127); // if failed to start, exit anyway
10306 } else if (parent.pid == -1) {
10307 retval = errno; // failed to fork
10308 }
10309#endif
10310 }
10311 parent.status = parent.pid > 0 ? 0 : -1; // if didn't start, set error status
10312 return retval;
10313}
10314
10315// --- command.apm_proc.apm.StartRead
10316// Start subprocess & Read output
10317algo::Fildes command::apm_StartRead(command::apm_proc& parent, algo_lib::FFildes &read) {
10318 int pipefd[2];
10319 int rc=pipe(pipefd);
10320 (void)rc;
10321 read.fd.value = pipefd[0];
10322 parent.fstdout << ">&" << pipefd[1];
10323 apm_Start(parent);
10324 (void)close(pipefd[1]);
10325 return read.fd;
10326}
10327
10328// --- command.apm_proc.apm.Kill
10329// Kill subprocess and wait
10330void command::apm_Kill(command::apm_proc& parent) {
10331 if (parent.pid != 0) {
10332 kill(parent.pid,9);
10333 apm_Wait(parent);
10334 }
10335}
10336
10337// --- command.apm_proc.apm.Wait
10338// Wait for subprocess to return
10339void command::apm_Wait(command::apm_proc& parent) {
10340 if (parent.pid > 0) {
10341 int wait_flags = 0;
10342 int wait_status = 0;
10343 int rc = -1;
10344 do {
10345 // really wait for subprocess to exit
10346 rc = waitpid(parent.pid,&wait_status,wait_flags);
10347 } while (rc==-1 && errno==EINTR);
10348 if (rc == parent.pid) {
10349 parent.status = wait_status;
10350 parent.pid = 0;
10351 }
10352 }
10353}
10354
10355// --- command.apm_proc.apm.Exec
10356// Start + Wait
10357// Execute subprocess and return exit code
10358int command::apm_Exec(command::apm_proc& parent) {
10359 apm_Start(parent);
10360 apm_Wait(parent);
10361 return parent.status;
10362}
10363
10364// --- command.apm_proc.apm.ExecX
10365// Start + Wait, throw exception on error
10366// Execute subprocess; throw human-readable exception on error
10367void command::apm_ExecX(command::apm_proc& parent) {
10368 int rc = apm_Exec(parent);
10369 vrfy(rc==0, tempstr() << "algo_lib.exec" << Keyval("cmd",apm_ToCmdline(parent))
10370 << Keyval("comment",algo::DescribeWaitStatus(parent.status)));
10371}
10372
10373// --- command.apm_proc.apm.Execv
10374// Call execv()
10375// Call execv with specified parameters
10376int command::apm_Execv(command::apm_proc& parent) {
10377 int ret = 0;
10378 algo::StringAry args;
10379 apm_ToArgv(parent, args);
10380 char **argv = (char**)alloca((ary_N(args)+1)*sizeof(*argv));
10381 ind_beg(algo::StringAry_ary_curs,arg,args) {
10382 argv[ind_curs(arg).index] = Zeroterm(arg);
10383 }ind_end;
10384 argv[ary_N(args)] = NULL;
10385 // if parent.path is relative, search for it in PATH
10386 algo_lib::ResolveExecFname(parent.path);
10387 ret = execv(Zeroterm(parent.path),argv);
10388 return ret;
10389}
10390
10391// --- command.apm_proc.apm.ToCmdline
10392algo::tempstr command::apm_ToCmdline(command::apm_proc& parent) {
10393 algo::tempstr retval;
10394 retval << parent.path << " ";
10395 command::apm_PrintArgv(parent.cmd,retval);
10396 if (ch_N(parent.fstdin)) {
10397 retval << " " << parent.fstdin;
10398 }
10399 if (ch_N(parent.fstdout)) {
10400 retval << " " << parent.fstdout;
10401 }
10402 if (ch_N(parent.fstderr)) {
10403 retval << " 2" << parent.fstderr;
10404 }
10405 return retval;
10406}
10407
10408// --- command.apm_proc.apm.ToArgv
10409// Form array from the command line
10410void command::apm_ToArgv(command::apm_proc& parent, algo::StringAry& args) {
10411 ary_RemoveAll(args);
10412 ary_Alloc(args) << parent.path;
10413
10414 if (parent.cmd.in != "data") {
10415 cstring *arg = &ary_Alloc(args);
10416 *arg << "-in:";
10417 cstring_Print(parent.cmd.in, *arg);
10418 }
10419
10420 if (parent.cmd.pkgdata != "") {
10421 cstring *arg = &ary_Alloc(args);
10422 *arg << "-pkgdata:";
10423 cstring_Print(parent.cmd.pkgdata, *arg);
10424 }
10425
10426 if (parent.cmd.package.expr != "") {
10427 cstring *arg = &ary_Alloc(args);
10428 *arg << "-package:";
10429 command::package_Print(parent.cmd, *arg);
10430 }
10431
10432 if (parent.cmd.ns.expr != "") {
10433 cstring *arg = &ary_Alloc(args);
10434 *arg << "-ns:";
10435 command::ns_Print(parent.cmd, *arg);
10436 }
10437
10438 if (parent.cmd.install != false) {
10439 cstring *arg = &ary_Alloc(args);
10440 *arg << "-install:";
10441 bool_Print(parent.cmd.install, *arg);
10442 }
10443
10444 if (parent.cmd.update != false) {
10445 cstring *arg = &ary_Alloc(args);
10446 *arg << "-update:";
10447 bool_Print(parent.cmd.update, *arg);
10448 }
10449
10450 if (parent.cmd.list != false) {
10451 cstring *arg = &ary_Alloc(args);
10452 *arg << "-list:";
10453 bool_Print(parent.cmd.list, *arg);
10454 }
10455
10456 if (parent.cmd.diff != false) {
10457 cstring *arg = &ary_Alloc(args);
10458 *arg << "-diff:";
10459 bool_Print(parent.cmd.diff, *arg);
10460 }
10461
10462 if (parent.cmd.push != false) {
10463 cstring *arg = &ary_Alloc(args);
10464 *arg << "-push:";
10465 bool_Print(parent.cmd.push, *arg);
10466 }
10467
10468 if (parent.cmd.check != false) {
10469 cstring *arg = &ary_Alloc(args);
10470 *arg << "-check:";
10471 bool_Print(parent.cmd.check, *arg);
10472 }
10473
10474 if (parent.cmd.remove != false) {
10475 cstring *arg = &ary_Alloc(args);
10476 *arg << "-remove:";
10477 bool_Print(parent.cmd.remove, *arg);
10478 }
10479
10480 if (parent.cmd.origin != "") {
10481 cstring *arg = &ary_Alloc(args);
10482 *arg << "-origin:";
10483 Smallstr200_Print(parent.cmd.origin, *arg);
10484 }
10485
10486 if (parent.cmd.ref != "") {
10487 cstring *arg = &ary_Alloc(args);
10488 *arg << "-ref:";
10489 Smallstr50_Print(parent.cmd.ref, *arg);
10490 }
10491
10492 if (parent.cmd.dry_run != false) {
10493 cstring *arg = &ary_Alloc(args);
10494 *arg << "-dry_run:";
10495 bool_Print(parent.cmd.dry_run, *arg);
10496 }
10497
10498 if (parent.cmd.showrec != false) {
10499 cstring *arg = &ary_Alloc(args);
10500 *arg << "-showrec:";
10501 bool_Print(parent.cmd.showrec, *arg);
10502 }
10503
10504 if (parent.cmd.showfile != false) {
10505 cstring *arg = &ary_Alloc(args);
10506 *arg << "-showfile:";
10507 bool_Print(parent.cmd.showfile, *arg);
10508 }
10509
10510 if (parent.cmd.R != false) {
10511 cstring *arg = &ary_Alloc(args);
10512 *arg << "-R:";
10513 bool_Print(parent.cmd.R, *arg);
10514 }
10515
10516 if (parent.cmd.l != false) {
10517 cstring *arg = &ary_Alloc(args);
10518 *arg << "-l:";
10519 bool_Print(parent.cmd.l, *arg);
10520 }
10521
10522 if (parent.cmd.reset != false) {
10523 cstring *arg = &ary_Alloc(args);
10524 *arg << "-reset:";
10525 bool_Print(parent.cmd.reset, *arg);
10526 }
10527
10528 if (parent.cmd.checkclean != true) {
10529 cstring *arg = &ary_Alloc(args);
10530 *arg << "-checkclean:";
10531 bool_Print(parent.cmd.checkclean, *arg);
10532 }
10533
10534 if (parent.cmd.t != false) {
10535 cstring *arg = &ary_Alloc(args);
10536 *arg << "-t:";
10537 bool_Print(parent.cmd.t, *arg);
10538 }
10539
10540 if (parent.cmd.stat != false) {
10541 cstring *arg = &ary_Alloc(args);
10542 *arg << "-stat:";
10543 bool_Print(parent.cmd.stat, *arg);
10544 }
10545
10546 if (parent.cmd.annotate != "") {
10547 cstring *arg = &ary_Alloc(args);
10548 *arg << "-annotate:";
10549 cstring_Print(parent.cmd.annotate, *arg);
10550 }
10551
10552 if (parent.cmd.data_in != "data") {
10553 cstring *arg = &ary_Alloc(args);
10554 *arg << "-data_in:";
10555 cstring_Print(parent.cmd.data_in, *arg);
10556 }
10557
10558 if (parent.cmd.e != false) {
10559 cstring *arg = &ary_Alloc(args);
10560 *arg << "-e:";
10561 bool_Print(parent.cmd.e, *arg);
10562 }
10563
10564 if (parent.cmd.binpath != "bin") {
10565 cstring *arg = &ary_Alloc(args);
10566 *arg << "-binpath:";
10567 cstring_Print(parent.cmd.binpath, *arg);
10568 }
10569 for (int i=1; i < algo_lib::_db.cmdline.verbose; ++i) {
10570 ary_Alloc(args) << "-verbose";
10571 }
10572}
10573
10574// --- command.apm_proc..Uninit
10575void command::apm_proc_Uninit(command::apm_proc& parent) {
10576 command::apm_proc &row = parent; (void)row;
10577
10578 // command.apm_proc.apm.Uninit (Exec) //
10579 apm_Kill(parent); // kill child, ensure forward progress
10580}
10581
10582// --- command.atf_amc.amctest.Print
10583// Print back to string
10584void command::amctest_Print(command::atf_amc& parent, algo::cstring &out) {
10585 Regx_Print(parent.amctest, out);
10586}
10587
10588// --- command.atf_amc.amctest.ReadStrptrMaybe
10589// Read Regx from string
10590// Convert string to field. Return success value
10591bool command::amctest_ReadStrptrMaybe(command::atf_amc& parent, algo::strptr in) {
10592 bool retval = true;
10593 Regx_ReadSql(parent.amctest, in, true);
10594 return retval;
10595}
10596
10597// --- command.atf_amc..ReadFieldMaybe
10598bool command::atf_amc_ReadFieldMaybe(command::atf_amc& parent, algo::strptr field, algo::strptr strval) {
10599 bool retval = true;
10600 command::FieldId field_id;
10601 (void)value_SetStrptrMaybe(field_id,field);
10602 switch(field_id) {
10603 case command_FieldId_in: {
10604 retval = algo::cstring_ReadStrptrMaybe(parent.in, strval);
10605 break;
10606 }
10607 case command_FieldId_amctest: {
10608 retval = amctest_ReadStrptrMaybe(parent, strval);
10609 break;
10610 }
10611 case command_FieldId_dofork: {
10612 retval = bool_ReadStrptrMaybe(parent.dofork, strval);
10613 break;
10614 }
10615 case command_FieldId_q: {
10616 retval = bool_ReadStrptrMaybe(parent.q, strval);
10617 break;
10618 }
10619 default: break;
10620 }
10621 if (!retval) {
10622 algo_lib::AppendErrtext("attr",field);
10623 }
10624 return retval;
10625}
10626
10627// --- command.atf_amc..ReadTupleMaybe
10628// Read fields of command::atf_amc from attributes of ascii tuple TUPLE
10629bool command::atf_amc_ReadTupleMaybe(command::atf_amc &parent, algo::Tuple &tuple) {
10630 bool retval = true;
10631 int anon_idx = 0;
10632 ind_beg(algo::Tuple_attrs_curs,attr,tuple) {
10633 if (ch_N(attr.name) == 0) {
10634 attr.name = atf_amc_GetAnon(parent, anon_idx++);
10635 }
10636 retval = atf_amc_ReadFieldMaybe(parent, attr.name, attr.value);
10637 if (!retval) {
10638 break;
10639 }
10640 }ind_end;
10641 return retval;
10642}
10643
10644// --- command.atf_amc..Init
10645// Set all fields to initial values.
10646void command::atf_amc_Init(command::atf_amc& parent) {
10647 parent.in = algo::strptr("data");
10648 Regx_ReadSql(parent.amctest, "%", true);
10649 parent.dofork = bool(true);
10650 parent.q = bool(false);
10651}
10652
10653// --- command.atf_amc..ToCmdline
10654// Convenience function that returns a full command line
10655// Assume command is in a directory called bin
10656tempstr command::atf_amc_ToCmdline(command::atf_amc& row) {
10657 tempstr ret;
10658 ret << "bin/atf_amc ";
10659 atf_amc_PrintArgv(row, ret);
10660 // inherit less intense verbose, debug options
10661 for (int i = 1; i < algo_lib::_db.cmdline.verbose; i++) {
10662 ret << " -verbose";
10663 }
10664 for (int i = 1; i < algo_lib::_db.cmdline.debug; i++) {
10665 ret << " -debug";
10666 }
10667 return ret;
10668}
10669
10670// --- command.atf_amc..PrintArgv
10671// print string representation of ROW to string STR
10672// cfmt:command.atf_amc.Argv printfmt:Tuple
10673void command::atf_amc_PrintArgv(command::atf_amc& row, algo::cstring& str) {
10674 algo::tempstr temp;
10675 (void)temp;
10676 (void)str;
10677 if (!(row.in == "data")) {
10678 ch_RemoveAll(temp);
10679 cstring_Print(row.in, temp);
10680 str << " -in:";
10681 strptr_PrintBash(temp,str);
10682 }
10683 ch_RemoveAll(temp);
10684 command::amctest_Print(const_cast<command::atf_amc&>(row), temp);
10685 str << " -amctest:";
10686 strptr_PrintBash(temp,str);
10687 if (!(row.dofork == true)) {
10688 ch_RemoveAll(temp);
10689 bool_Print(row.dofork, temp);
10690 str << " -dofork:";
10691 strptr_PrintBash(temp,str);
10692 }
10693 if (!(row.q == false)) {
10694 ch_RemoveAll(temp);
10695 bool_Print(row.q, temp);
10696 str << " -q:";
10697 strptr_PrintBash(temp,str);
10698 }
10699}
10700
10701// --- command.atf_amc..GetAnon
10702algo::strptr command::atf_amc_GetAnon(command::atf_amc &parent, i32 idx) {
10703 (void)parent;//only to avoid -Wunused-parameter
10704 switch(idx) {
10705 case(0): return strptr("amctest", 7);
10706 default: return algo::strptr();
10707 }
10708}
10709
10710// --- command.atf_amc..NArgs
10711// Used with command lines
10712// Return # of command-line arguments that must follow this argument
10713// If FIELD is invalid, return -1
10714i32 command::atf_amc_NArgs(command::FieldId field, algo::strptr& out_dflt, bool* out_anon) {
10715 i32 retval = 1;
10716 switch (field) {
10717 case command_FieldId_in: { // $comment
10718 *out_anon = false;
10719 } break;
10720 case command_FieldId_amctest: { // $comment
10721 *out_anon = true;
10722 } break;
10723 case command_FieldId_dofork: { // $comment
10724 *out_anon = false;
10725 retval=0;
10726 out_dflt="Y";
10727 } break;
10728 case command_FieldId_q: { // bool: no argument required but value may be specified as dofork:Y
10729 *out_anon = false;
10730 retval=0;
10731 out_dflt="Y";
10732 } break;
10733 default:
10734 retval=-1; // unrecognized
10735 }
10736 return retval;
10737}
10738
10739// --- command.atf_amc_proc.atf_amc.Start
10740// Start subprocess
10741// If subprocess already running, do nothing. Otherwise, start it
10742int command::atf_amc_Start(command::atf_amc_proc& parent) {
10743 int retval = 0;
10744 if (parent.pid == 0) {
10745 verblog(atf_amc_ToCmdline(parent)); // maybe print command
10746#ifdef WIN32
10747 algo_lib::ResolveExecFname(parent.path);
10748 tempstr cmdline(atf_amc_ToCmdline(parent));
10749 parent.pid = dospawn(Zeroterm(parent.path),Zeroterm(cmdline),parent.timeout,parent.fstdin,parent.fstdout,parent.fstderr);
10750#else
10751 parent.pid = fork();
10752 if (parent.pid == 0) { // child
10753 algo_lib::DieWithParent();
10754 if (parent.timeout > 0) {
10755 alarm(parent.timeout);
10756 }
10757 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstdin , 0);
10758 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstdout, 1);
10759 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstderr, 2);
10760 if (retval==0) retval= atf_amc_Execv(parent);
10761 if (retval != 0) { // if start fails, print error
10762 int err=errno;
10763 prerr("command.atf_amc_execv"
10764 <<Keyval("errno",err)
10765 <<Keyval("errstr",strerror(err))
10766 <<Keyval("comment","Execv failed"));
10767 }
10768 _exit(127); // if failed to start, exit anyway
10769 } else if (parent.pid == -1) {
10770 retval = errno; // failed to fork
10771 }
10772#endif
10773 }
10774 parent.status = parent.pid > 0 ? 0 : -1; // if didn't start, set error status
10775 return retval;
10776}
10777
10778// --- command.atf_amc_proc.atf_amc.StartRead
10779// Start subprocess & Read output
10780algo::Fildes command::atf_amc_StartRead(command::atf_amc_proc& parent, algo_lib::FFildes &read) {
10781 int pipefd[2];
10782 int rc=pipe(pipefd);
10783 (void)rc;
10784 read.fd.value = pipefd[0];
10785 parent.fstdout << ">&" << pipefd[1];
10786 atf_amc_Start(parent);
10787 (void)close(pipefd[1]);
10788 return read.fd;
10789}
10790
10791// --- command.atf_amc_proc.atf_amc.Kill
10792// Kill subprocess and wait
10793void command::atf_amc_Kill(command::atf_amc_proc& parent) {
10794 if (parent.pid != 0) {
10795 kill(parent.pid,9);
10796 atf_amc_Wait(parent);
10797 }
10798}
10799
10800// --- command.atf_amc_proc.atf_amc.Wait
10801// Wait for subprocess to return
10802void command::atf_amc_Wait(command::atf_amc_proc& parent) {
10803 if (parent.pid > 0) {
10804 int wait_flags = 0;
10805 int wait_status = 0;
10806 int rc = -1;
10807 do {
10808 // really wait for subprocess to exit
10809 rc = waitpid(parent.pid,&wait_status,wait_flags);
10810 } while (rc==-1 && errno==EINTR);
10811 if (rc == parent.pid) {
10812 parent.status = wait_status;
10813 parent.pid = 0;
10814 }
10815 }
10816}
10817
10818// --- command.atf_amc_proc.atf_amc.Exec
10819// Start + Wait
10820// Execute subprocess and return exit code
10821int command::atf_amc_Exec(command::atf_amc_proc& parent) {
10822 atf_amc_Start(parent);
10823 atf_amc_Wait(parent);
10824 return parent.status;
10825}
10826
10827// --- command.atf_amc_proc.atf_amc.ExecX
10828// Start + Wait, throw exception on error
10829// Execute subprocess; throw human-readable exception on error
10830void command::atf_amc_ExecX(command::atf_amc_proc& parent) {
10831 int rc = atf_amc_Exec(parent);
10832 vrfy(rc==0, tempstr() << "algo_lib.exec" << Keyval("cmd",atf_amc_ToCmdline(parent))
10833 << Keyval("comment",algo::DescribeWaitStatus(parent.status)));
10834}
10835
10836// --- command.atf_amc_proc.atf_amc.Execv
10837// Call execv()
10838// Call execv with specified parameters
10839int command::atf_amc_Execv(command::atf_amc_proc& parent) {
10840 int ret = 0;
10841 algo::StringAry args;
10842 atf_amc_ToArgv(parent, args);
10843 char **argv = (char**)alloca((ary_N(args)+1)*sizeof(*argv));
10844 ind_beg(algo::StringAry_ary_curs,arg,args) {
10845 argv[ind_curs(arg).index] = Zeroterm(arg);
10846 }ind_end;
10847 argv[ary_N(args)] = NULL;
10848 // if parent.path is relative, search for it in PATH
10849 algo_lib::ResolveExecFname(parent.path);
10850 ret = execv(Zeroterm(parent.path),argv);
10851 return ret;
10852}
10853
10854// --- command.atf_amc_proc.atf_amc.ToCmdline
10855algo::tempstr command::atf_amc_ToCmdline(command::atf_amc_proc& parent) {
10856 algo::tempstr retval;
10857 retval << parent.path << " ";
10858 command::atf_amc_PrintArgv(parent.cmd,retval);
10859 if (ch_N(parent.fstdin)) {
10860 retval << " " << parent.fstdin;
10861 }
10862 if (ch_N(parent.fstdout)) {
10863 retval << " " << parent.fstdout;
10864 }
10865 if (ch_N(parent.fstderr)) {
10866 retval << " 2" << parent.fstderr;
10867 }
10868 return retval;
10869}
10870
10871// --- command.atf_amc_proc.atf_amc.ToArgv
10872// Form array from the command line
10873void command::atf_amc_ToArgv(command::atf_amc_proc& parent, algo::StringAry& args) {
10874 ary_RemoveAll(args);
10875 ary_Alloc(args) << parent.path;
10876
10877 if (parent.cmd.in != "data") {
10878 cstring *arg = &ary_Alloc(args);
10879 *arg << "-in:";
10880 cstring_Print(parent.cmd.in, *arg);
10881 }
10882
10883 if (parent.cmd.amctest.expr != "%") {
10884 cstring *arg = &ary_Alloc(args);
10885 *arg << "-amctest:";
10886 command::amctest_Print(parent.cmd, *arg);
10887 }
10888
10889 if (parent.cmd.dofork != true) {
10890 cstring *arg = &ary_Alloc(args);
10891 *arg << "-dofork:";
10892 bool_Print(parent.cmd.dofork, *arg);
10893 }
10894
10895 if (parent.cmd.q != false) {
10896 cstring *arg = &ary_Alloc(args);
10897 *arg << "-q:";
10898 bool_Print(parent.cmd.q, *arg);
10899 }
10900 for (int i=1; i < algo_lib::_db.cmdline.verbose; ++i) {
10901 ary_Alloc(args) << "-verbose";
10902 }
10903}
10904
10905// --- command.atf_amc_proc..Uninit
10906void command::atf_amc_proc_Uninit(command::atf_amc_proc& parent) {
10907 command::atf_amc_proc &row = parent; (void)row;
10908
10909 // command.atf_amc_proc.atf_amc.Uninit (Exec) //
10910 atf_amc_Kill(parent); // kill child, ensure forward progress
10911}
10912
10913// --- command.atf_ci.citest.Print
10914// Print back to string
10915void command::citest_Print(command::atf_ci& parent, algo::cstring &out) {
10916 Regx_Print(parent.citest, out);
10917}
10918
10919// --- command.atf_ci.citest.ReadStrptrMaybe
10920// Read Regx from string
10921// Convert string to field. Return success value
10922bool command::citest_ReadStrptrMaybe(command::atf_ci& parent, algo::strptr in) {
10923 bool retval = true;
10924 Regx_ReadSql(parent.citest, in, true);
10925 return retval;
10926}
10927
10928// --- command.atf_ci.cijob.Print
10929// Print back to string
10930void command::cijob_Print(command::atf_ci& parent, algo::cstring &out) {
10931 Regx_Print(parent.cijob, out);
10932}
10933
10934// --- command.atf_ci.cijob.ReadStrptrMaybe
10935// Read Regx from string
10936// Convert string to field. Return success value
10937bool command::cijob_ReadStrptrMaybe(command::atf_ci& parent, algo::strptr in) {
10938 bool retval = true;
10939 Regx_ReadSql(parent.cijob, in, true);
10940 return retval;
10941}
10942
10943// --- command.atf_ci..ReadFieldMaybe
10944bool command::atf_ci_ReadFieldMaybe(command::atf_ci& parent, algo::strptr field, algo::strptr strval) {
10945 bool retval = true;
10946 command::FieldId field_id;
10947 (void)value_SetStrptrMaybe(field_id,field);
10948 switch(field_id) {
10949 case command_FieldId_in: {
10950 retval = algo::cstring_ReadStrptrMaybe(parent.in, strval);
10951 break;
10952 }
10953 case command_FieldId_citest: {
10954 retval = citest_ReadStrptrMaybe(parent, strval);
10955 break;
10956 }
10957 case command_FieldId_maxerr: {
10958 retval = i32_ReadStrptrMaybe(parent.maxerr, strval);
10959 break;
10960 }
10961 case command_FieldId_cijob: {
10962 retval = cijob_ReadStrptrMaybe(parent, strval);
10963 break;
10964 }
10965 case command_FieldId_capture: {
10966 retval = bool_ReadStrptrMaybe(parent.capture, strval);
10967 break;
10968 }
10969 default: break;
10970 }
10971 if (!retval) {
10972 algo_lib::AppendErrtext("attr",field);
10973 }
10974 return retval;
10975}
10976
10977// --- command.atf_ci..ReadTupleMaybe
10978// Read fields of command::atf_ci from attributes of ascii tuple TUPLE
10979bool command::atf_ci_ReadTupleMaybe(command::atf_ci &parent, algo::Tuple &tuple) {
10980 bool retval = true;
10981 int anon_idx = 0;
10982 ind_beg(algo::Tuple_attrs_curs,attr,tuple) {
10983 if (ch_N(attr.name) == 0) {
10984 attr.name = atf_ci_GetAnon(parent, anon_idx++);
10985 }
10986 retval = atf_ci_ReadFieldMaybe(parent, attr.name, attr.value);
10987 if (!retval) {
10988 break;
10989 }
10990 }ind_end;
10991 return retval;
10992}
10993
10994// --- command.atf_ci..Init
10995// Set all fields to initial values.
10996void command::atf_ci_Init(command::atf_ci& parent) {
10997 parent.in = algo::strptr("data");
10998 Regx_ReadSql(parent.citest, "%", true);
10999 parent.maxerr = i32(0);
11000 Regx_ReadSql(parent.cijob, "%", true);
11001 parent.capture = bool(false);
11002}
11003
11004// --- command.atf_ci..ToCmdline
11005// Convenience function that returns a full command line
11006// Assume command is in a directory called bin
11007tempstr command::atf_ci_ToCmdline(command::atf_ci& row) {
11008 tempstr ret;
11009 ret << "bin/atf_ci ";
11010 atf_ci_PrintArgv(row, ret);
11011 // inherit less intense verbose, debug options
11012 for (int i = 1; i < algo_lib::_db.cmdline.verbose; i++) {
11013 ret << " -verbose";
11014 }
11015 for (int i = 1; i < algo_lib::_db.cmdline.debug; i++) {
11016 ret << " -debug";
11017 }
11018 return ret;
11019}
11020
11021// --- command.atf_ci..PrintArgv
11022// print string representation of ROW to string STR
11023// cfmt:command.atf_ci.Argv printfmt:Tuple
11024void command::atf_ci_PrintArgv(command::atf_ci& row, algo::cstring& str) {
11025 algo::tempstr temp;
11026 (void)temp;
11027 (void)str;
11028 if (!(row.in == "data")) {
11029 ch_RemoveAll(temp);
11030 cstring_Print(row.in, temp);
11031 str << " -in:";
11032 strptr_PrintBash(temp,str);
11033 }
11034 ch_RemoveAll(temp);
11035 command::citest_Print(const_cast<command::atf_ci&>(row), temp);
11036 str << " -citest:";
11037 strptr_PrintBash(temp,str);
11038 if (!(row.maxerr == 0)) {
11039 ch_RemoveAll(temp);
11040 i32_Print(row.maxerr, temp);
11041 str << " -maxerr:";
11042 strptr_PrintBash(temp,str);
11043 }
11044 if (!(row.cijob.expr == "%")) {
11045 ch_RemoveAll(temp);
11046 command::cijob_Print(const_cast<command::atf_ci&>(row), temp);
11047 str << " -cijob:";
11048 strptr_PrintBash(temp,str);
11049 }
11050 if (!(row.capture == false)) {
11051 ch_RemoveAll(temp);
11052 bool_Print(row.capture, temp);
11053 str << " -capture:";
11054 strptr_PrintBash(temp,str);
11055 }
11056}
11057
11058// --- command.atf_ci..GetAnon
11059algo::strptr command::atf_ci_GetAnon(command::atf_ci &parent, i32 idx) {
11060 (void)parent;//only to avoid -Wunused-parameter
11061 switch(idx) {
11062 case(0): return strptr("citest", 6);
11063 default: return algo::strptr();
11064 }
11065}
11066
11067// --- command.atf_ci..NArgs
11068// Used with command lines
11069// Return # of command-line arguments that must follow this argument
11070// If FIELD is invalid, return -1
11071i32 command::atf_ci_NArgs(command::FieldId field, algo::strptr& out_dflt, bool* out_anon) {
11072 i32 retval = 1;
11073 switch (field) {
11074 case command_FieldId_in: { // $comment
11075 *out_anon = false;
11076 } break;
11077 case command_FieldId_citest: { // $comment
11078 *out_anon = true;
11079 } break;
11080 case command_FieldId_maxerr: { // $comment
11081 *out_anon = false;
11082 } break;
11083 case command_FieldId_cijob: { // $comment
11084 *out_anon = false;
11085 } break;
11086 case command_FieldId_capture: { // $comment
11087 *out_anon = false;
11088 retval=0;
11089 out_dflt="Y";
11090 } break;
11091 default:
11092 retval=-1; // unrecognized
11093 }
11094 return retval;
11095}
11096
11097// --- command.atf_ci_proc.atf_ci.Start
11098// Start subprocess
11099// If subprocess already running, do nothing. Otherwise, start it
11100int command::atf_ci_Start(command::atf_ci_proc& parent) {
11101 int retval = 0;
11102 if (parent.pid == 0) {
11103 verblog(atf_ci_ToCmdline(parent)); // maybe print command
11104#ifdef WIN32
11105 algo_lib::ResolveExecFname(parent.path);
11106 tempstr cmdline(atf_ci_ToCmdline(parent));
11107 parent.pid = dospawn(Zeroterm(parent.path),Zeroterm(cmdline),parent.timeout,parent.fstdin,parent.fstdout,parent.fstderr);
11108#else
11109 parent.pid = fork();
11110 if (parent.pid == 0) { // child
11111 algo_lib::DieWithParent();
11112 if (parent.timeout > 0) {
11113 alarm(parent.timeout);
11114 }
11115 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstdin , 0);
11116 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstdout, 1);
11117 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstderr, 2);
11118 if (retval==0) retval= atf_ci_Execv(parent);
11119 if (retval != 0) { // if start fails, print error
11120 int err=errno;
11121 prerr("command.atf_ci_execv"
11122 <<Keyval("errno",err)
11123 <<Keyval("errstr",strerror(err))
11124 <<Keyval("comment","Execv failed"));
11125 }
11126 _exit(127); // if failed to start, exit anyway
11127 } else if (parent.pid == -1) {
11128 retval = errno; // failed to fork
11129 }
11130#endif
11131 }
11132 parent.status = parent.pid > 0 ? 0 : -1; // if didn't start, set error status
11133 return retval;
11134}
11135
11136// --- command.atf_ci_proc.atf_ci.StartRead
11137// Start subprocess & Read output
11138algo::Fildes command::atf_ci_StartRead(command::atf_ci_proc& parent, algo_lib::FFildes &read) {
11139 int pipefd[2];
11140 int rc=pipe(pipefd);
11141 (void)rc;
11142 read.fd.value = pipefd[0];
11143 parent.fstdout << ">&" << pipefd[1];
11144 atf_ci_Start(parent);
11145 (void)close(pipefd[1]);
11146 return read.fd;
11147}
11148
11149// --- command.atf_ci_proc.atf_ci.Kill
11150// Kill subprocess and wait
11151void command::atf_ci_Kill(command::atf_ci_proc& parent) {
11152 if (parent.pid != 0) {
11153 kill(parent.pid,9);
11154 atf_ci_Wait(parent);
11155 }
11156}
11157
11158// --- command.atf_ci_proc.atf_ci.Wait
11159// Wait for subprocess to return
11160void command::atf_ci_Wait(command::atf_ci_proc& parent) {
11161 if (parent.pid > 0) {
11162 int wait_flags = 0;
11163 int wait_status = 0;
11164 int rc = -1;
11165 do {
11166 // really wait for subprocess to exit
11167 rc = waitpid(parent.pid,&wait_status,wait_flags);
11168 } while (rc==-1 && errno==EINTR);
11169 if (rc == parent.pid) {
11170 parent.status = wait_status;
11171 parent.pid = 0;
11172 }
11173 }
11174}
11175
11176// --- command.atf_ci_proc.atf_ci.Exec
11177// Start + Wait
11178// Execute subprocess and return exit code
11179int command::atf_ci_Exec(command::atf_ci_proc& parent) {
11180 atf_ci_Start(parent);
11181 atf_ci_Wait(parent);
11182 return parent.status;
11183}
11184
11185// --- command.atf_ci_proc.atf_ci.ExecX
11186// Start + Wait, throw exception on error
11187// Execute subprocess; throw human-readable exception on error
11188void command::atf_ci_ExecX(command::atf_ci_proc& parent) {
11189 int rc = atf_ci_Exec(parent);
11190 vrfy(rc==0, tempstr() << "algo_lib.exec" << Keyval("cmd",atf_ci_ToCmdline(parent))
11191 << Keyval("comment",algo::DescribeWaitStatus(parent.status)));
11192}
11193
11194// --- command.atf_ci_proc.atf_ci.Execv
11195// Call execv()
11196// Call execv with specified parameters
11197int command::atf_ci_Execv(command::atf_ci_proc& parent) {
11198 int ret = 0;
11199 algo::StringAry args;
11200 atf_ci_ToArgv(parent, args);
11201 char **argv = (char**)alloca((ary_N(args)+1)*sizeof(*argv));
11202 ind_beg(algo::StringAry_ary_curs,arg,args) {
11203 argv[ind_curs(arg).index] = Zeroterm(arg);
11204 }ind_end;
11205 argv[ary_N(args)] = NULL;
11206 // if parent.path is relative, search for it in PATH
11207 algo_lib::ResolveExecFname(parent.path);
11208 ret = execv(Zeroterm(parent.path),argv);
11209 return ret;
11210}
11211
11212// --- command.atf_ci_proc.atf_ci.ToCmdline
11213algo::tempstr command::atf_ci_ToCmdline(command::atf_ci_proc& parent) {
11214 algo::tempstr retval;
11215 retval << parent.path << " ";
11216 command::atf_ci_PrintArgv(parent.cmd,retval);
11217 if (ch_N(parent.fstdin)) {
11218 retval << " " << parent.fstdin;
11219 }
11220 if (ch_N(parent.fstdout)) {
11221 retval << " " << parent.fstdout;
11222 }
11223 if (ch_N(parent.fstderr)) {
11224 retval << " 2" << parent.fstderr;
11225 }
11226 return retval;
11227}
11228
11229// --- command.atf_ci_proc.atf_ci.ToArgv
11230// Form array from the command line
11231void command::atf_ci_ToArgv(command::atf_ci_proc& parent, algo::StringAry& args) {
11232 ary_RemoveAll(args);
11233 ary_Alloc(args) << parent.path;
11234
11235 if (parent.cmd.in != "data") {
11236 cstring *arg = &ary_Alloc(args);
11237 *arg << "-in:";
11238 cstring_Print(parent.cmd.in, *arg);
11239 }
11240
11241 if (parent.cmd.citest.expr != "%") {
11242 cstring *arg = &ary_Alloc(args);
11243 *arg << "-citest:";
11244 command::citest_Print(parent.cmd, *arg);
11245 }
11246
11247 if (parent.cmd.maxerr != 0) {
11248 cstring *arg = &ary_Alloc(args);
11249 *arg << "-maxerr:";
11250 i32_Print(parent.cmd.maxerr, *arg);
11251 }
11252
11253 if (parent.cmd.cijob.expr != "%") {
11254 cstring *arg = &ary_Alloc(args);
11255 *arg << "-cijob:";
11256 command::cijob_Print(parent.cmd, *arg);
11257 }
11258
11259 if (parent.cmd.capture != false) {
11260 cstring *arg = &ary_Alloc(args);
11261 *arg << "-capture:";
11262 bool_Print(parent.cmd.capture, *arg);
11263 }
11264 for (int i=1; i < algo_lib::_db.cmdline.verbose; ++i) {
11265 ary_Alloc(args) << "-verbose";
11266 }
11267}
11268
11269// --- command.atf_ci_proc..Uninit
11270void command::atf_ci_proc_Uninit(command::atf_ci_proc& parent) {
11271 command::atf_ci_proc &row = parent; (void)row;
11272
11273 // command.atf_ci_proc.atf_ci.Uninit (Exec) //
11274 atf_ci_Kill(parent); // kill child, ensure forward progress
11275}
11276
11277// --- command.atf_cmdline.mstr.Addary
11278// Reserve space (this may move memory). Insert N element at the end.
11279// Return aryptr to newly inserted block.
11280// If the RHS argument aliases the array (refers to the same memory), exit program with fatal error.
11281algo::aryptr<algo::cstring> command::mstr_Addary(command::atf_cmdline& parent, algo::aryptr<algo::cstring> rhs) {
11282 bool overlaps = rhs.n_elems>0 && rhs.elems >= parent.mstr_elems && rhs.elems < parent.mstr_elems + parent.mstr_max;
11283 if (UNLIKELY(overlaps)) {
11284 FatalErrorExit("command.tary_alias field:command.atf_cmdline.mstr comment:'alias error: sub-array is being appended to the whole'");
11285 }
11286 int nnew = rhs.n_elems;
11287 mstr_Reserve(parent, nnew); // reserve space
11288 int at = parent.mstr_n;
11289 for (int i = 0; i < nnew; i++) {
11290 new (parent.mstr_elems + at + i) algo::cstring(rhs[i]);
11291 parent.mstr_n++;
11292 }
11293 return algo::aryptr<algo::cstring>(parent.mstr_elems + at, nnew);
11294}
11295
11296// --- command.atf_cmdline.mstr.Alloc
11297// Reserve space. Insert element at the end
11298// The new element is initialized to a default value
11299algo::cstring& command::mstr_Alloc(command::atf_cmdline& parent) {
11300 mstr_Reserve(parent, 1);
11301 int n = parent.mstr_n;
11302 int at = n;
11303 algo::cstring *elems = parent.mstr_elems;
11304 new (elems + at) algo::cstring(); // construct new element, default initializer
11305 parent.mstr_n = n+1;
11306 return elems[at];
11307}
11308
11309// --- command.atf_cmdline.mstr.AllocAt
11310// Reserve space for new element, reallocating the array if necessary
11311// Insert new element at specified index. Index must be in range or a fatal error occurs.
11312algo::cstring& command::mstr_AllocAt(command::atf_cmdline& parent, int at) {
11313 mstr_Reserve(parent, 1);
11314 int n = parent.mstr_n;
11315 if (UNLIKELY(u64(at) >= u64(n+1))) {
11316 FatalErrorExit("command.bad_alloc_at field:command.atf_cmdline.mstr comment:'index out of range'");
11317 }
11318 algo::cstring *elems = parent.mstr_elems;
11319 memmove(elems + at + 1, elems + at, (n - at) * sizeof(algo::cstring));
11320 new (elems + at) algo::cstring(); // construct element, default initializer
11321 parent.mstr_n = n+1;
11322 return elems[at];
11323}
11324
11325// --- command.atf_cmdline.mstr.AllocN
11326// Reserve space. Insert N elements at the end of the array, return pointer to array
11327algo::aryptr<algo::cstring> command::mstr_AllocN(command::atf_cmdline& parent, int n_elems) {
11328 mstr_Reserve(parent, n_elems);
11329 int old_n = parent.mstr_n;
11330 int new_n = old_n + n_elems;
11331 algo::cstring *elems = parent.mstr_elems;
11332 for (int i = old_n; i < new_n; i++) {
11333 new (elems + i) algo::cstring(); // construct new element, default initialize
11334 }
11335 parent.mstr_n = new_n;
11336 return algo::aryptr<algo::cstring>(elems + old_n, n_elems);
11337}
11338
11339// --- command.atf_cmdline.mstr.Remove
11340// Remove item by index. If index outside of range, do nothing.
11341void command::mstr_Remove(command::atf_cmdline& parent, u32 i) {
11342 u32 lim = parent.mstr_n;
11343 algo::cstring *elems = parent.mstr_elems;
11344 if (i < lim) {
11345 elems[i].~cstring(); // destroy element
11346 memmove(elems + i, elems + (i + 1), sizeof(algo::cstring) * (lim - (i + 1)));
11347 parent.mstr_n = lim - 1;
11348 }
11349}
11350
11351// --- command.atf_cmdline.mstr.RemoveAll
11352void command::mstr_RemoveAll(command::atf_cmdline& parent) {
11353 u32 n = parent.mstr_n;
11354 while (n > 0) {
11355 n -= 1;
11356 parent.mstr_elems[n].~cstring();
11357 parent.mstr_n = n;
11358 }
11359}
11360
11361// --- command.atf_cmdline.mstr.RemoveLast
11362// Delete last element of array. Do nothing if array is empty.
11363void command::mstr_RemoveLast(command::atf_cmdline& parent) {
11364 u64 n = parent.mstr_n;
11365 if (n > 0) {
11366 n -= 1;
11367 mstr_qFind(parent, u64(n)).~cstring();
11368 parent.mstr_n = n;
11369 }
11370}
11371
11372// --- command.atf_cmdline.mstr.AbsReserve
11373// Make sure N elements fit in array. Process dies if out of memory
11374void command::mstr_AbsReserve(command::atf_cmdline& parent, int n) {
11375 u32 old_max = parent.mstr_max;
11376 if (n > i32(old_max)) {
11377 u32 new_max = i32_Max(i32_Max(old_max * 2, n), 4);
11378 void *new_mem = algo_lib::malloc_ReallocMem(parent.mstr_elems, old_max * sizeof(algo::cstring), new_max * sizeof(algo::cstring));
11379 if (UNLIKELY(!new_mem)) {
11380 FatalErrorExit("command.tary_nomem field:command.atf_cmdline.mstr comment:'out of memory'");
11381 }
11382 parent.mstr_elems = (algo::cstring*)new_mem;
11383 parent.mstr_max = new_max;
11384 }
11385}
11386
11387// --- command.atf_cmdline.mstr.Setary
11388// Copy contents of RHS to PARENT.
11389void command::mstr_Setary(command::atf_cmdline& parent, command::atf_cmdline &rhs) {
11390 mstr_RemoveAll(parent);
11391 int nnew = rhs.mstr_n;
11392 mstr_Reserve(parent, nnew); // reserve space
11393 for (int i = 0; i < nnew; i++) { // copy elements over
11394 new (parent.mstr_elems + i) algo::cstring(mstr_qFind(rhs, i));
11395 parent.mstr_n = i + 1;
11396 }
11397}
11398
11399// --- command.atf_cmdline.mstr.Setary2
11400// Copy specified array into mstr, discarding previous contents.
11401// If the RHS argument aliases the array (refers to the same memory), throw exception.
11402void command::mstr_Setary(command::atf_cmdline& parent, const algo::aryptr<algo::cstring> &rhs) {
11403 mstr_RemoveAll(parent);
11404 mstr_Addary(parent, rhs);
11405}
11406
11407// --- command.atf_cmdline.mstr.AllocNVal
11408// Reserve space. Insert N elements at the end of the array, return pointer to array
11409algo::aryptr<algo::cstring> command::mstr_AllocNVal(command::atf_cmdline& parent, int n_elems, const algo::cstring& val) {
11410 mstr_Reserve(parent, n_elems);
11411 int old_n = parent.mstr_n;
11412 int new_n = old_n + n_elems;
11413 algo::cstring *elems = parent.mstr_elems;
11414 for (int i = old_n; i < new_n; i++) {
11415 new (elems + i) algo::cstring(val);
11416 }
11417 parent.mstr_n = new_n;
11418 return algo::aryptr<algo::cstring>(elems + old_n, n_elems);
11419}
11420
11421// --- command.atf_cmdline.mstr.ReadStrptrMaybe
11422// A single element is read from input string and appended to the array.
11423// If the string contains an error, the array is untouched.
11424// Function returns success value.
11425bool command::mstr_ReadStrptrMaybe(command::atf_cmdline& parent, algo::strptr in_str) {
11426 bool retval = true;
11427 algo::cstring &elem = mstr_Alloc(parent);
11428 retval = algo::cstring_ReadStrptrMaybe(elem, in_str);
11429 if (!retval) {
11430 mstr_RemoveLast(parent);
11431 }
11432 return retval;
11433}
11434
11435// --- command.atf_cmdline.mnum.Addary
11436// Reserve space (this may move memory). Insert N element at the end.
11437// Return aryptr to newly inserted block.
11438// If the RHS argument aliases the array (refers to the same memory), exit program with fatal error.
11439algo::aryptr<i32> command::mnum_Addary(command::atf_cmdline& parent, algo::aryptr<i32> rhs) {
11440 bool overlaps = rhs.n_elems>0 && rhs.elems >= parent.mnum_elems && rhs.elems < parent.mnum_elems + parent.mnum_max;
11441 if (UNLIKELY(overlaps)) {
11442 FatalErrorExit("command.tary_alias field:command.atf_cmdline.mnum comment:'alias error: sub-array is being appended to the whole'");
11443 }
11444 int nnew = rhs.n_elems;
11445 mnum_Reserve(parent, nnew); // reserve space
11446 int at = parent.mnum_n;
11447 memcpy(parent.mnum_elems + at, rhs.elems, nnew * sizeof(i32));
11448 parent.mnum_n += nnew;
11449 return algo::aryptr<i32>(parent.mnum_elems + at, nnew);
11450}
11451
11452// --- command.atf_cmdline.mnum.Alloc
11453// Reserve space. Insert element at the end
11454// The new element is initialized to a default value
11455i32& command::mnum_Alloc(command::atf_cmdline& parent) {
11456 mnum_Reserve(parent, 1);
11457 int n = parent.mnum_n;
11458 int at = n;
11459 i32 *elems = parent.mnum_elems;
11460 new (elems + at) i32(0); // construct new element, default initializer
11461 parent.mnum_n = n+1;
11462 return elems[at];
11463}
11464
11465// --- command.atf_cmdline.mnum.AllocAt
11466// Reserve space for new element, reallocating the array if necessary
11467// Insert new element at specified index. Index must be in range or a fatal error occurs.
11468i32& command::mnum_AllocAt(command::atf_cmdline& parent, int at) {
11469 mnum_Reserve(parent, 1);
11470 int n = parent.mnum_n;
11471 if (UNLIKELY(u64(at) >= u64(n+1))) {
11472 FatalErrorExit("command.bad_alloc_at field:command.atf_cmdline.mnum comment:'index out of range'");
11473 }
11474 i32 *elems = parent.mnum_elems;
11475 memmove(elems + at + 1, elems + at, (n - at) * sizeof(i32));
11476 new (elems + at) i32(0); // construct element, default initializer
11477 parent.mnum_n = n+1;
11478 return elems[at];
11479}
11480
11481// --- command.atf_cmdline.mnum.AllocN
11482// Reserve space. Insert N elements at the end of the array, return pointer to array
11483algo::aryptr<i32> command::mnum_AllocN(command::atf_cmdline& parent, int n_elems) {
11484 mnum_Reserve(parent, n_elems);
11485 int old_n = parent.mnum_n;
11486 int new_n = old_n + n_elems;
11487 i32 *elems = parent.mnum_elems;
11488 for (int i = old_n; i < new_n; i++) {
11489 new (elems + i) i32(0); // construct new element, default initialize
11490 }
11491 parent.mnum_n = new_n;
11492 return algo::aryptr<i32>(elems + old_n, n_elems);
11493}
11494
11495// --- command.atf_cmdline.mnum.Remove
11496// Remove item by index. If index outside of range, do nothing.
11497void command::mnum_Remove(command::atf_cmdline& parent, u32 i) {
11498 u32 lim = parent.mnum_n;
11499 i32 *elems = parent.mnum_elems;
11500 if (i < lim) {
11501 memmove(elems + i, elems + (i + 1), sizeof(i32) * (lim - (i + 1)));
11502 parent.mnum_n = lim - 1;
11503 }
11504}
11505
11506// --- command.atf_cmdline.mnum.RemoveLast
11507// Delete last element of array. Do nothing if array is empty.
11508void command::mnum_RemoveLast(command::atf_cmdline& parent) {
11509 u64 n = parent.mnum_n;
11510 if (n > 0) {
11511 n -= 1;
11512 parent.mnum_n = n;
11513 }
11514}
11515
11516// --- command.atf_cmdline.mnum.AbsReserve
11517// Make sure N elements fit in array. Process dies if out of memory
11518void command::mnum_AbsReserve(command::atf_cmdline& parent, int n) {
11519 u32 old_max = parent.mnum_max;
11520 if (n > i32(old_max)) {
11521 u32 new_max = i32_Max(i32_Max(old_max * 2, n), 4);
11522 void *new_mem = algo_lib::malloc_ReallocMem(parent.mnum_elems, old_max * sizeof(i32), new_max * sizeof(i32));
11523 if (UNLIKELY(!new_mem)) {
11524 FatalErrorExit("command.tary_nomem field:command.atf_cmdline.mnum comment:'out of memory'");
11525 }
11526 parent.mnum_elems = (i32*)new_mem;
11527 parent.mnum_max = new_max;
11528 }
11529}
11530
11531// --- command.atf_cmdline.mnum.Setary
11532// Copy contents of RHS to PARENT.
11533void command::mnum_Setary(command::atf_cmdline& parent, command::atf_cmdline &rhs) {
11534 mnum_RemoveAll(parent);
11535 int nnew = rhs.mnum_n;
11536 mnum_Reserve(parent, nnew); // reserve space
11537 for (int i = 0; i < nnew; i++) { // copy elements over
11538 new (parent.mnum_elems + i) i32(mnum_qFind(rhs, i));
11539 parent.mnum_n = i + 1;
11540 }
11541}
11542
11543// --- command.atf_cmdline.mnum.Setary2
11544// Copy specified array into mnum, discarding previous contents.
11545// If the RHS argument aliases the array (refers to the same memory), throw exception.
11546void command::mnum_Setary(command::atf_cmdline& parent, const algo::aryptr<i32> &rhs) {
11547 mnum_RemoveAll(parent);
11548 mnum_Addary(parent, rhs);
11549}
11550
11551// --- command.atf_cmdline.mnum.AllocNVal
11552// Reserve space. Insert N elements at the end of the array, return pointer to array
11553algo::aryptr<i32> command::mnum_AllocNVal(command::atf_cmdline& parent, int n_elems, const i32& val) {
11554 mnum_Reserve(parent, n_elems);
11555 int old_n = parent.mnum_n;
11556 int new_n = old_n + n_elems;
11557 i32 *elems = parent.mnum_elems;
11558 for (int i = old_n; i < new_n; i++) {
11559 new (elems + i) i32(val);
11560 }
11561 parent.mnum_n = new_n;
11562 return algo::aryptr<i32>(elems + old_n, n_elems);
11563}
11564
11565// --- command.atf_cmdline.mnum.ReadStrptrMaybe
11566// A single element is read from input string and appended to the array.
11567// If the string contains an error, the array is untouched.
11568// Function returns success value.
11569bool command::mnum_ReadStrptrMaybe(command::atf_cmdline& parent, algo::strptr in_str) {
11570 bool retval = true;
11571 i32 &elem = mnum_Alloc(parent);
11572 retval = i32_ReadStrptrMaybe(elem, in_str);
11573 if (!retval) {
11574 mnum_RemoveLast(parent);
11575 }
11576 return retval;
11577}
11578
11579// --- command.atf_cmdline.mdbl.Addary
11580// Reserve space (this may move memory). Insert N element at the end.
11581// Return aryptr to newly inserted block.
11582// If the RHS argument aliases the array (refers to the same memory), exit program with fatal error.
11583algo::aryptr<double> command::mdbl_Addary(command::atf_cmdline& parent, algo::aryptr<double> rhs) {
11584 bool overlaps = rhs.n_elems>0 && rhs.elems >= parent.mdbl_elems && rhs.elems < parent.mdbl_elems + parent.mdbl_max;
11585 if (UNLIKELY(overlaps)) {
11586 FatalErrorExit("command.tary_alias field:command.atf_cmdline.mdbl comment:'alias error: sub-array is being appended to the whole'");
11587 }
11588 int nnew = rhs.n_elems;
11589 mdbl_Reserve(parent, nnew); // reserve space
11590 int at = parent.mdbl_n;
11591 memcpy(parent.mdbl_elems + at, rhs.elems, nnew * sizeof(double));
11592 parent.mdbl_n += nnew;
11593 return algo::aryptr<double>(parent.mdbl_elems + at, nnew);
11594}
11595
11596// --- command.atf_cmdline.mdbl.Alloc
11597// Reserve space. Insert element at the end
11598// The new element is initialized to a default value
11599double& command::mdbl_Alloc(command::atf_cmdline& parent) {
11600 mdbl_Reserve(parent, 1);
11601 int n = parent.mdbl_n;
11602 int at = n;
11603 double *elems = parent.mdbl_elems;
11604 new (elems + at) double(0.0); // construct new element, default initializer
11605 parent.mdbl_n = n+1;
11606 return elems[at];
11607}
11608
11609// --- command.atf_cmdline.mdbl.AllocAt
11610// Reserve space for new element, reallocating the array if necessary
11611// Insert new element at specified index. Index must be in range or a fatal error occurs.
11612double& command::mdbl_AllocAt(command::atf_cmdline& parent, int at) {
11613 mdbl_Reserve(parent, 1);
11614 int n = parent.mdbl_n;
11615 if (UNLIKELY(u64(at) >= u64(n+1))) {
11616 FatalErrorExit("command.bad_alloc_at field:command.atf_cmdline.mdbl comment:'index out of range'");
11617 }
11618 double *elems = parent.mdbl_elems;
11619 memmove(elems + at + 1, elems + at, (n - at) * sizeof(double));
11620 new (elems + at) double(0.0); // construct element, default initializer
11621 parent.mdbl_n = n+1;
11622 return elems[at];
11623}
11624
11625// --- command.atf_cmdline.mdbl.AllocN
11626// Reserve space. Insert N elements at the end of the array, return pointer to array
11627algo::aryptr<double> command::mdbl_AllocN(command::atf_cmdline& parent, int n_elems) {
11628 mdbl_Reserve(parent, n_elems);
11629 int old_n = parent.mdbl_n;
11630 int new_n = old_n + n_elems;
11631 double *elems = parent.mdbl_elems;
11632 for (int i = old_n; i < new_n; i++) {
11633 new (elems + i) double(0.0); // construct new element, default initialize
11634 }
11635 parent.mdbl_n = new_n;
11636 return algo::aryptr<double>(elems + old_n, n_elems);
11637}
11638
11639// --- command.atf_cmdline.mdbl.Remove
11640// Remove item by index. If index outside of range, do nothing.
11641void command::mdbl_Remove(command::atf_cmdline& parent, u32 i) {
11642 u32 lim = parent.mdbl_n;
11643 double *elems = parent.mdbl_elems;
11644 if (i < lim) {
11645 memmove(elems + i, elems + (i + 1), sizeof(double) * (lim - (i + 1)));
11646 parent.mdbl_n = lim - 1;
11647 }
11648}
11649
11650// --- command.atf_cmdline.mdbl.RemoveLast
11651// Delete last element of array. Do nothing if array is empty.
11652void command::mdbl_RemoveLast(command::atf_cmdline& parent) {
11653 u64 n = parent.mdbl_n;
11654 if (n > 0) {
11655 n -= 1;
11656 parent.mdbl_n = n;
11657 }
11658}
11659
11660// --- command.atf_cmdline.mdbl.AbsReserve
11661// Make sure N elements fit in array. Process dies if out of memory
11662void command::mdbl_AbsReserve(command::atf_cmdline& parent, int n) {
11663 u32 old_max = parent.mdbl_max;
11664 if (n > i32(old_max)) {
11665 u32 new_max = i32_Max(i32_Max(old_max * 2, n), 4);
11666 void *new_mem = algo_lib::malloc_ReallocMem(parent.mdbl_elems, old_max * sizeof(double), new_max * sizeof(double));
11667 if (UNLIKELY(!new_mem)) {
11668 FatalErrorExit("command.tary_nomem field:command.atf_cmdline.mdbl comment:'out of memory'");
11669 }
11670 parent.mdbl_elems = (double*)new_mem;
11671 parent.mdbl_max = new_max;
11672 }
11673}
11674
11675// --- command.atf_cmdline.mdbl.Setary
11676// Copy contents of RHS to PARENT.
11677void command::mdbl_Setary(command::atf_cmdline& parent, command::atf_cmdline &rhs) {
11678 mdbl_RemoveAll(parent);
11679 int nnew = rhs.mdbl_n;
11680 mdbl_Reserve(parent, nnew); // reserve space
11681 for (int i = 0; i < nnew; i++) { // copy elements over
11682 new (parent.mdbl_elems + i) double(mdbl_qFind(rhs, i));
11683 parent.mdbl_n = i + 1;
11684 }
11685}
11686
11687// --- command.atf_cmdline.mdbl.Setary2
11688// Copy specified array into mdbl, discarding previous contents.
11689// If the RHS argument aliases the array (refers to the same memory), throw exception.
11690void command::mdbl_Setary(command::atf_cmdline& parent, const algo::aryptr<double> &rhs) {
11691 mdbl_RemoveAll(parent);
11692 mdbl_Addary(parent, rhs);
11693}
11694
11695// --- command.atf_cmdline.mdbl.AllocNVal
11696// Reserve space. Insert N elements at the end of the array, return pointer to array
11697algo::aryptr<double> command::mdbl_AllocNVal(command::atf_cmdline& parent, int n_elems, const double& val) {
11698 mdbl_Reserve(parent, n_elems);
11699 int old_n = parent.mdbl_n;
11700 int new_n = old_n + n_elems;
11701 double *elems = parent.mdbl_elems;
11702 for (int i = old_n; i < new_n; i++) {
11703 new (elems + i) double(val);
11704 }
11705 parent.mdbl_n = new_n;
11706 return algo::aryptr<double>(elems + old_n, n_elems);
11707}
11708
11709// --- command.atf_cmdline.mdbl.ReadStrptrMaybe
11710// A single element is read from input string and appended to the array.
11711// If the string contains an error, the array is untouched.
11712// Function returns success value.
11713bool command::mdbl_ReadStrptrMaybe(command::atf_cmdline& parent, algo::strptr in_str) {
11714 bool retval = true;
11715 double &elem = mdbl_Alloc(parent);
11716 retval = double_ReadStrptrMaybe(elem, in_str);
11717 if (!retval) {
11718 mdbl_RemoveLast(parent);
11719 }
11720 return retval;
11721}
11722
11723// --- command.atf_cmdline.amnum.Addary
11724// Reserve space (this may move memory). Insert N element at the end.
11725// Return aryptr to newly inserted block.
11726// If the RHS argument aliases the array (refers to the same memory), exit program with fatal error.
11727algo::aryptr<i32> command::amnum_Addary(command::atf_cmdline& parent, algo::aryptr<i32> rhs) {
11728 bool overlaps = rhs.n_elems>0 && rhs.elems >= parent.amnum_elems && rhs.elems < parent.amnum_elems + parent.amnum_max;
11729 if (UNLIKELY(overlaps)) {
11730 FatalErrorExit("command.tary_alias field:command.atf_cmdline.amnum comment:'alias error: sub-array is being appended to the whole'");
11731 }
11732 int nnew = rhs.n_elems;
11733 amnum_Reserve(parent, nnew); // reserve space
11734 int at = parent.amnum_n;
11735 memcpy(parent.amnum_elems + at, rhs.elems, nnew * sizeof(i32));
11736 parent.amnum_n += nnew;
11737 return algo::aryptr<i32>(parent.amnum_elems + at, nnew);
11738}
11739
11740// --- command.atf_cmdline.amnum.Alloc
11741// Reserve space. Insert element at the end
11742// The new element is initialized to a default value
11743i32& command::amnum_Alloc(command::atf_cmdline& parent) {
11744 amnum_Reserve(parent, 1);
11745 int n = parent.amnum_n;
11746 int at = n;
11747 i32 *elems = parent.amnum_elems;
11748 new (elems + at) i32(0); // construct new element, default initializer
11749 parent.amnum_n = n+1;
11750 return elems[at];
11751}
11752
11753// --- command.atf_cmdline.amnum.AllocAt
11754// Reserve space for new element, reallocating the array if necessary
11755// Insert new element at specified index. Index must be in range or a fatal error occurs.
11756i32& command::amnum_AllocAt(command::atf_cmdline& parent, int at) {
11757 amnum_Reserve(parent, 1);
11758 int n = parent.amnum_n;
11759 if (UNLIKELY(u64(at) >= u64(n+1))) {
11760 FatalErrorExit("command.bad_alloc_at field:command.atf_cmdline.amnum comment:'index out of range'");
11761 }
11762 i32 *elems = parent.amnum_elems;
11763 memmove(elems + at + 1, elems + at, (n - at) * sizeof(i32));
11764 new (elems + at) i32(0); // construct element, default initializer
11765 parent.amnum_n = n+1;
11766 return elems[at];
11767}
11768
11769// --- command.atf_cmdline.amnum.AllocN
11770// Reserve space. Insert N elements at the end of the array, return pointer to array
11771algo::aryptr<i32> command::amnum_AllocN(command::atf_cmdline& parent, int n_elems) {
11772 amnum_Reserve(parent, n_elems);
11773 int old_n = parent.amnum_n;
11774 int new_n = old_n + n_elems;
11775 i32 *elems = parent.amnum_elems;
11776 for (int i = old_n; i < new_n; i++) {
11777 new (elems + i) i32(0); // construct new element, default initialize
11778 }
11779 parent.amnum_n = new_n;
11780 return algo::aryptr<i32>(elems + old_n, n_elems);
11781}
11782
11783// --- command.atf_cmdline.amnum.Remove
11784// Remove item by index. If index outside of range, do nothing.
11785void command::amnum_Remove(command::atf_cmdline& parent, u32 i) {
11786 u32 lim = parent.amnum_n;
11787 i32 *elems = parent.amnum_elems;
11788 if (i < lim) {
11789 memmove(elems + i, elems + (i + 1), sizeof(i32) * (lim - (i + 1)));
11790 parent.amnum_n = lim - 1;
11791 }
11792}
11793
11794// --- command.atf_cmdline.amnum.RemoveLast
11795// Delete last element of array. Do nothing if array is empty.
11796void command::amnum_RemoveLast(command::atf_cmdline& parent) {
11797 u64 n = parent.amnum_n;
11798 if (n > 0) {
11799 n -= 1;
11800 parent.amnum_n = n;
11801 }
11802}
11803
11804// --- command.atf_cmdline.amnum.AbsReserve
11805// Make sure N elements fit in array. Process dies if out of memory
11806void command::amnum_AbsReserve(command::atf_cmdline& parent, int n) {
11807 u32 old_max = parent.amnum_max;
11808 if (n > i32(old_max)) {
11809 u32 new_max = i32_Max(i32_Max(old_max * 2, n), 4);
11810 void *new_mem = algo_lib::malloc_ReallocMem(parent.amnum_elems, old_max * sizeof(i32), new_max * sizeof(i32));
11811 if (UNLIKELY(!new_mem)) {
11812 FatalErrorExit("command.tary_nomem field:command.atf_cmdline.amnum comment:'out of memory'");
11813 }
11814 parent.amnum_elems = (i32*)new_mem;
11815 parent.amnum_max = new_max;
11816 }
11817}
11818
11819// --- command.atf_cmdline.amnum.Setary
11820// Copy contents of RHS to PARENT.
11821void command::amnum_Setary(command::atf_cmdline& parent, command::atf_cmdline &rhs) {
11822 amnum_RemoveAll(parent);
11823 int nnew = rhs.amnum_n;
11824 amnum_Reserve(parent, nnew); // reserve space
11825 for (int i = 0; i < nnew; i++) { // copy elements over
11826 new (parent.amnum_elems + i) i32(amnum_qFind(rhs, i));
11827 parent.amnum_n = i + 1;
11828 }
11829}
11830
11831// --- command.atf_cmdline.amnum.Setary2
11832// Copy specified array into amnum, discarding previous contents.
11833// If the RHS argument aliases the array (refers to the same memory), throw exception.
11834void command::amnum_Setary(command::atf_cmdline& parent, const algo::aryptr<i32> &rhs) {
11835 amnum_RemoveAll(parent);
11836 amnum_Addary(parent, rhs);
11837}
11838
11839// --- command.atf_cmdline.amnum.AllocNVal
11840// Reserve space. Insert N elements at the end of the array, return pointer to array
11841algo::aryptr<i32> command::amnum_AllocNVal(command::atf_cmdline& parent, int n_elems, const i32& val) {
11842 amnum_Reserve(parent, n_elems);
11843 int old_n = parent.amnum_n;
11844 int new_n = old_n + n_elems;
11845 i32 *elems = parent.amnum_elems;
11846 for (int i = old_n; i < new_n; i++) {
11847 new (elems + i) i32(val);
11848 }
11849 parent.amnum_n = new_n;
11850 return algo::aryptr<i32>(elems + old_n, n_elems);
11851}
11852
11853// --- command.atf_cmdline.amnum.ReadStrptrMaybe
11854// A single element is read from input string and appended to the array.
11855// If the string contains an error, the array is untouched.
11856// Function returns success value.
11857bool command::amnum_ReadStrptrMaybe(command::atf_cmdline& parent, algo::strptr in_str) {
11858 bool retval = true;
11859 i32 &elem = amnum_Alloc(parent);
11860 retval = i32_ReadStrptrMaybe(elem, in_str);
11861 if (!retval) {
11862 amnum_RemoveLast(parent);
11863 }
11864 return retval;
11865}
11866
11867// --- command.atf_cmdline.fconst.ToCstr
11868// Convert numeric value of field to one of predefined string constants.
11869// If string is found, return a static C string. Otherwise, return NULL.
11870const char* command::fconst_ToCstr(const command::atf_cmdline& parent) {
11871 const char *ret = NULL;
11872 switch(fconst_GetEnum(parent)) {
11873 case command_atf_cmdline_fconst_high: ret = "high"; break;
11874 case command_atf_cmdline_fconst_medium: ret = "medium"; break;
11875 case command_atf_cmdline_fconst_low: ret = "low"; break;
11876 }
11877 return ret;
11878}
11879
11880// --- command.atf_cmdline.fconst.Print
11881// Convert fconst to a string. First, attempt conversion to a known string.
11882// If no string matches, print fconst as a numeric value.
11883void command::fconst_Print(const command::atf_cmdline& parent, algo::cstring &lhs) {
11884 const char *strval = fconst_ToCstr(parent);
11885 if (strval) {
11886 lhs << strval;
11887 } else {
11888 lhs << parent.fconst;
11889 }
11890}
11891
11892// --- command.atf_cmdline.fconst.SetStrptrMaybe
11893// Convert string to field.
11894// If the string is invalid, do not modify field and return false.
11895// In case of success, return true
11896bool command::fconst_SetStrptrMaybe(command::atf_cmdline& parent, algo::strptr rhs) {
11897 bool ret = false;
11898 switch (elems_N(rhs)) {
11899 case 3: {
11900 switch (u64(algo::ReadLE16(rhs.elems))|(u64(rhs[2])<<16)) {
11901 case LE_STR3('l','o','w'): {
11902 fconst_SetEnum(parent,command_atf_cmdline_fconst_low); ret = true; break;
11903 }
11904 }
11905 break;
11906 }
11907 case 4: {
11908 switch (u64(algo::ReadLE32(rhs.elems))) {
11909 case LE_STR4('h','i','g','h'): {
11910 fconst_SetEnum(parent,command_atf_cmdline_fconst_high); ret = true; break;
11911 }
11912 }
11913 break;
11914 }
11915 case 6: {
11916 switch (u64(algo::ReadLE32(rhs.elems))|(u64(algo::ReadLE16(rhs.elems+4))<<32)) {
11917 case LE_STR6('m','e','d','i','u','m'): {
11918 fconst_SetEnum(parent,command_atf_cmdline_fconst_medium); ret = true; break;
11919 }
11920 }
11921 break;
11922 }
11923 }
11924 return ret;
11925}
11926
11927// --- command.atf_cmdline.fconst.SetStrptr
11928// Convert string to field.
11929// If the string is invalid, set numeric value to DFLT
11930void command::fconst_SetStrptr(command::atf_cmdline& parent, algo::strptr rhs, command_atf_cmdline_fconst_Enum dflt) {
11931 if (!fconst_SetStrptrMaybe(parent,rhs)) fconst_SetEnum(parent,dflt);
11932}
11933
11934// --- command.atf_cmdline.fconst.ReadStrptrMaybe
11935// Convert string to field. Return success value
11936bool command::fconst_ReadStrptrMaybe(command::atf_cmdline& parent, algo::strptr rhs) {
11937 bool retval = false;
11938 retval = fconst_SetStrptrMaybe(parent,rhs); // try symbol conversion
11939 if (!retval) { // didn't work? try reading as underlying type
11940 retval = u8_ReadStrptrMaybe(parent.fconst,rhs);
11941 }
11942 return retval;
11943}
11944
11945// --- command.atf_cmdline.dregx.Print
11946// Print back to string
11947void command::dregx_Print(command::atf_cmdline& parent, algo::cstring &out) {
11948 Regx_Print(parent.dregx, out);
11949}
11950
11951// --- command.atf_cmdline.dregx.ReadStrptrMaybe
11952// Read Regx from string
11953// Convert string to field. Return success value
11954bool command::dregx_ReadStrptrMaybe(command::atf_cmdline& parent, algo::strptr in) {
11955 bool retval = true;
11956 Regx_ReadSql(parent.dregx, in, true);
11957 return retval;
11958}
11959
11960// --- command.atf_cmdline..ReadFieldMaybe
11961bool command::atf_cmdline_ReadFieldMaybe(command::atf_cmdline& parent, algo::strptr field, algo::strptr strval) {
11962 bool retval = true;
11963 command::FieldId field_id;
11964 (void)value_SetStrptrMaybe(field_id,algo::Pathcomp(field, ".LL"));
11965 switch(field_id) {
11966 case command_FieldId_in: {
11967 retval = algo::cstring_ReadStrptrMaybe(parent.in, strval);
11968 break;
11969 }
11970 case command_FieldId_exec: {
11971 retval = bool_ReadStrptrMaybe(parent.exec, strval);
11972 break;
11973 }
11974 case command_FieldId_astr: {
11975 retval = algo::cstring_ReadStrptrMaybe(parent.astr, strval);
11976 break;
11977 }
11978 case command_FieldId_anum: {
11979 retval = i32_ReadStrptrMaybe(parent.anum, strval);
11980 break;
11981 }
11982 case command_FieldId_adbl: {
11983 retval = double_ReadStrptrMaybe(parent.adbl, strval);
11984 break;
11985 }
11986 case command_FieldId_aflag: {
11987 retval = bool_ReadStrptrMaybe(parent.aflag, strval);
11988 break;
11989 }
11990 case command_FieldId_str: {
11991 retval = algo::cstring_ReadStrptrMaybe(parent.str, strval);
11992 break;
11993 }
11994 case command_FieldId_num: {
11995 retval = i32_ReadStrptrMaybe(parent.num, strval);
11996 break;
11997 }
11998 case command_FieldId_dbl: {
11999 retval = double_ReadStrptrMaybe(parent.dbl, strval);
12000 break;
12001 }
12002 case command_FieldId_flag: {
12003 retval = bool_ReadStrptrMaybe(parent.flag, strval);
12004 break;
12005 }
12006 case command_FieldId_dstr: {
12007 retval = algo::cstring_ReadStrptrMaybe(parent.dstr, strval);
12008 break;
12009 }
12010 case command_FieldId_dnum: {
12011 retval = i32_ReadStrptrMaybe(parent.dnum, strval);
12012 break;
12013 }
12014 case command_FieldId_ddbl: {
12015 retval = double_ReadStrptrMaybe(parent.ddbl, strval);
12016 break;
12017 }
12018 case command_FieldId_dflag: {
12019 retval = bool_ReadStrptrMaybe(parent.dflag, strval);
12020 break;
12021 }
12022 case command_FieldId_mstr: {
12023 retval = mstr_ReadStrptrMaybe(parent, strval);
12024 break;
12025 }
12026 case command_FieldId_mnum: {
12027 retval = mnum_ReadStrptrMaybe(parent, strval);
12028 break;
12029 }
12030 case command_FieldId_mdbl: {
12031 retval = mdbl_ReadStrptrMaybe(parent, strval);
12032 break;
12033 }
12034 case command_FieldId_amnum: {
12035 retval = amnum_ReadStrptrMaybe(parent, strval);
12036 break;
12037 }
12038 case command_FieldId_fconst: {
12039 retval = fconst_ReadStrptrMaybe(parent, strval);
12040 break;
12041 }
12042 case command_FieldId_cconst: {
12043 retval = algo::Month_ReadStrptrMaybe(parent.cconst, strval);
12044 break;
12045 }
12046 case command_FieldId_dregx: {
12047 retval = dregx_ReadStrptrMaybe(parent, strval);
12048 break;
12049 }
12050 case command_FieldId_dpkey: {
12051 retval = algo::Smallstr100_ReadStrptrMaybe(parent.dpkey, strval);
12052 break;
12053 }
12054 default: break;
12055 }
12056 if (!retval) {
12057 algo_lib::AppendErrtext("attr",field);
12058 }
12059 return retval;
12060}
12061
12062// --- command.atf_cmdline..ReadTupleMaybe
12063// Read fields of command::atf_cmdline from attributes of ascii tuple TUPLE
12064bool command::atf_cmdline_ReadTupleMaybe(command::atf_cmdline &parent, algo::Tuple &tuple) {
12065 bool retval = true;
12066 int anon_idx = 0;
12067 ind_beg(algo::Tuple_attrs_curs,attr,tuple) {
12068 if (ch_N(attr.name) == 0) {
12069 attr.name = atf_cmdline_GetAnon(parent, anon_idx++);
12070 }
12071 retval = atf_cmdline_ReadFieldMaybe(parent, attr.name, attr.value);
12072 if (!retval) {
12073 break;
12074 }
12075 }ind_end;
12076 return retval;
12077}
12078
12079// --- command.atf_cmdline..Init
12080// Set all fields to initial values.
12081void command::atf_cmdline_Init(command::atf_cmdline& parent) {
12082 parent.in = algo::strptr("data");
12083 parent.exec = bool(false);
12084 parent.anum = i32(0);
12085 parent.adbl = double(0.0);
12086 parent.aflag = bool(false);
12087 parent.num = i32(0);
12088 parent.dbl = double(0.0);
12089 parent.flag = bool(false);
12090 parent.dstr = algo::strptr("blah");
12091 parent.dnum = i32(-33);
12092 parent.ddbl = double(0.0001);
12093 parent.dflag = bool(true);
12094 parent.mstr_elems = 0; // (command.atf_cmdline.mstr)
12095 parent.mstr_n = 0; // (command.atf_cmdline.mstr)
12096 parent.mstr_max = 0; // (command.atf_cmdline.mstr)
12097 parent.mnum_elems = 0; // (command.atf_cmdline.mnum)
12098 parent.mnum_n = 0; // (command.atf_cmdline.mnum)
12099 parent.mnum_max = 0; // (command.atf_cmdline.mnum)
12100 parent.mdbl_elems = 0; // (command.atf_cmdline.mdbl)
12101 parent.mdbl_n = 0; // (command.atf_cmdline.mdbl)
12102 parent.mdbl_max = 0; // (command.atf_cmdline.mdbl)
12103 parent.amnum_elems = 0; // (command.atf_cmdline.amnum)
12104 parent.amnum_n = 0; // (command.atf_cmdline.amnum)
12105 parent.amnum_max = 0; // (command.atf_cmdline.amnum)
12106 parent.fconst = u8(0);
12107 Regx_ReadSql(parent.dregx, "%", true);
12108 parent.dpkey = algo::strptr("");
12109}
12110
12111// --- command.atf_cmdline..Uninit
12112void command::atf_cmdline_Uninit(command::atf_cmdline& parent) {
12113 command::atf_cmdline &row = parent; (void)row;
12114
12115 // command.atf_cmdline.amnum.Uninit (Tary) //Anon number array
12116 // remove all elements from command.atf_cmdline.amnum
12117 amnum_RemoveAll(parent);
12118 // free memory for Tary command.atf_cmdline.amnum
12119 algo_lib::malloc_FreeMem(parent.amnum_elems, sizeof(i32)*parent.amnum_max); // (command.atf_cmdline.amnum)
12120
12121 // command.atf_cmdline.mdbl.Uninit (Tary) //Double array
12122 // remove all elements from command.atf_cmdline.mdbl
12123 mdbl_RemoveAll(parent);
12124 // free memory for Tary command.atf_cmdline.mdbl
12125 algo_lib::malloc_FreeMem(parent.mdbl_elems, sizeof(double)*parent.mdbl_max); // (command.atf_cmdline.mdbl)
12126
12127 // command.atf_cmdline.mnum.Uninit (Tary) //Number array
12128 // remove all elements from command.atf_cmdline.mnum
12129 mnum_RemoveAll(parent);
12130 // free memory for Tary command.atf_cmdline.mnum
12131 algo_lib::malloc_FreeMem(parent.mnum_elems, sizeof(i32)*parent.mnum_max); // (command.atf_cmdline.mnum)
12132
12133 // command.atf_cmdline.mstr.Uninit (Tary) //String array
12134 // remove all elements from command.atf_cmdline.mstr
12135 mstr_RemoveAll(parent);
12136 // free memory for Tary command.atf_cmdline.mstr
12137 algo_lib::malloc_FreeMem(parent.mstr_elems, sizeof(algo::cstring)*parent.mstr_max); // (command.atf_cmdline.mstr)
12138}
12139
12140// --- command.atf_cmdline..ToCmdline
12141// Convenience function that returns a full command line
12142// Assume command is in a directory called bin
12143tempstr command::atf_cmdline_ToCmdline(command::atf_cmdline& row) {
12144 tempstr ret;
12145 ret << "bin/atf_cmdline ";
12146 atf_cmdline_PrintArgv(row, ret);
12147 // inherit less intense verbose, debug options
12148 for (int i = 1; i < algo_lib::_db.cmdline.verbose; i++) {
12149 ret << " -verbose";
12150 }
12151 for (int i = 1; i < algo_lib::_db.cmdline.debug; i++) {
12152 ret << " -debug";
12153 }
12154 return ret;
12155}
12156
12157// --- command.atf_cmdline..PrintArgv
12158// print string representation of ROW to string STR
12159// cfmt:command.atf_cmdline.Argv printfmt:Tuple
12160void command::atf_cmdline_PrintArgv(command::atf_cmdline& row, algo::cstring& str) {
12161 algo::tempstr temp;
12162 (void)temp;
12163 (void)str;
12164 if (!(row.in == "data")) {
12165 ch_RemoveAll(temp);
12166 cstring_Print(row.in, temp);
12167 str << " -in:";
12168 strptr_PrintBash(temp,str);
12169 }
12170 if (!(row.exec == false)) {
12171 ch_RemoveAll(temp);
12172 bool_Print(row.exec, temp);
12173 str << " -exec:";
12174 strptr_PrintBash(temp,str);
12175 }
12176 ch_RemoveAll(temp);
12177 cstring_Print(row.astr, temp);
12178 str << " -astr:";
12179 strptr_PrintBash(temp,str);
12180 ch_RemoveAll(temp);
12181 i32_Print(row.anum, temp);
12182 str << " -anum:";
12183 strptr_PrintBash(temp,str);
12184 ch_RemoveAll(temp);
12185 double_Print(row.adbl, temp);
12186 str << " -adbl:";
12187 strptr_PrintBash(temp,str);
12188 ch_RemoveAll(temp);
12189 bool_Print(row.aflag, temp);
12190 str << " -aflag:";
12191 strptr_PrintBash(temp,str);
12192 ch_RemoveAll(temp);
12193 cstring_Print(row.str, temp);
12194 str << " -str:";
12195 strptr_PrintBash(temp,str);
12196 if (!(row.num == 0)) {
12197 ch_RemoveAll(temp);
12198 i32_Print(row.num, temp);
12199 str << " -num:";
12200 strptr_PrintBash(temp,str);
12201 }
12202 if (!(row.dbl == 0.0)) {
12203 ch_RemoveAll(temp);
12204 double_Print(row.dbl, temp);
12205 str << " -dbl:";
12206 strptr_PrintBash(temp,str);
12207 }
12208 if (!(row.flag == false)) {
12209 ch_RemoveAll(temp);
12210 bool_Print(row.flag, temp);
12211 str << " -flag:";
12212 strptr_PrintBash(temp,str);
12213 }
12214 if (!(row.dstr == "blah")) {
12215 ch_RemoveAll(temp);
12216 cstring_Print(row.dstr, temp);
12217 str << " -dstr:";
12218 strptr_PrintBash(temp,str);
12219 }
12220 if (!(row.dnum == -33)) {
12221 ch_RemoveAll(temp);
12222 i32_Print(row.dnum, temp);
12223 str << " -dnum:";
12224 strptr_PrintBash(temp,str);
12225 }
12226 if (!(row.ddbl == 0.0001)) {
12227 ch_RemoveAll(temp);
12228 double_Print(row.ddbl, temp);
12229 str << " -ddbl:";
12230 strptr_PrintBash(temp,str);
12231 }
12232 if (!(row.dflag == true)) {
12233 ch_RemoveAll(temp);
12234 bool_Print(row.dflag, temp);
12235 str << " -dflag:";
12236 strptr_PrintBash(temp,str);
12237 }
12238 ind_beg(atf_cmdline_mstr_curs,value,row) {
12239 ch_RemoveAll(temp);
12240 cstring_Print(value, temp);
12241 str << " -mstr:";
12242 strptr_PrintBash(temp,str);
12243 }ind_end;
12244 ind_beg(atf_cmdline_mnum_curs,value,row) {
12245 ch_RemoveAll(temp);
12246 i32_Print(value, temp);
12247 str << " -mnum:";
12248 strptr_PrintBash(temp,str);
12249 }ind_end;
12250 ind_beg(atf_cmdline_mdbl_curs,value,row) {
12251 ch_RemoveAll(temp);
12252 double_Print(value, temp);
12253 str << " -mdbl:";
12254 strptr_PrintBash(temp,str);
12255 }ind_end;
12256 ind_beg(atf_cmdline_amnum_curs,value,row) {
12257 ch_RemoveAll(temp);
12258 i32_Print(value, temp);
12259 str << " -amnum:";
12260 strptr_PrintBash(temp,str);
12261 }ind_end;
12262 if (!(row.fconst == 0)) {
12263 ch_RemoveAll(temp);
12264 command::fconst_Print(const_cast<command::atf_cmdline&>(row), temp);
12265 str << " -fconst:";
12266 strptr_PrintBash(temp,str);
12267 }
12268 ch_RemoveAll(temp);
12269 Month_Print(row.cconst, temp);
12270 str << " -cconst:";
12271 strptr_PrintBash(temp,str);
12272 if (!(row.dregx.expr == "%")) {
12273 ch_RemoveAll(temp);
12274 command::dregx_Print(const_cast<command::atf_cmdline&>(row), temp);
12275 str << " -dregx:";
12276 strptr_PrintBash(temp,str);
12277 }
12278 if (!(row.dpkey == "")) {
12279 ch_RemoveAll(temp);
12280 Smallstr100_Print(row.dpkey, temp);
12281 str << " -dpkey:";
12282 strptr_PrintBash(temp,str);
12283 }
12284}
12285
12286// --- command.atf_cmdline..GetAnon
12287algo::strptr command::atf_cmdline_GetAnon(command::atf_cmdline &parent, i32 idx) {
12288 (void)parent;//only to avoid -Wunused-parameter
12289 switch(idx) {
12290 case(0): return strptr("astr", 4);
12291 case(1): return strptr("anum", 4);
12292 case(2): return strptr("adbl", 4);
12293 case(3): return strptr("aflag", 5);
12294 default: return strptr("amnum", 5);
12295 }
12296}
12297
12298// --- command.atf_cmdline..NArgs
12299// Used with command lines
12300// Return # of command-line arguments that must follow this argument
12301// If FIELD is invalid, return -1
12302i32 command::atf_cmdline_NArgs(command::FieldId field, algo::strptr& out_dflt, bool* out_anon) {
12303 i32 retval = 1;
12304 switch (field) {
12305 case command_FieldId_in: { // $comment
12306 *out_anon = false;
12307 } break;
12308 case command_FieldId_exec: { // $comment
12309 *out_anon = false;
12310 retval=0;
12311 out_dflt="Y";
12312 } break;
12313 case command_FieldId_astr: { // bool: no argument required but value may be specified as exec:Y
12314 *out_anon = true;
12315 } break;
12316 case command_FieldId_anum: { // bool: no argument required but value may be specified as exec:Y
12317 *out_anon = true;
12318 } break;
12319 case command_FieldId_adbl: { // bool: no argument required but value may be specified as exec:Y
12320 *out_anon = true;
12321 } break;
12322 case command_FieldId_aflag: { // bool: no argument required but value may be specified as exec:Y
12323 *out_anon = true;
12324 retval=0;
12325 out_dflt="Y";
12326 } break;
12327 case command_FieldId_str: { // bool: no argument required but value may be specified as aflag:Y
12328 *out_anon = false;
12329 } break;
12330 case command_FieldId_num: { // bool: no argument required but value may be specified as aflag:Y
12331 *out_anon = false;
12332 } break;
12333 case command_FieldId_dbl: { // bool: no argument required but value may be specified as aflag:Y
12334 *out_anon = false;
12335 } break;
12336 case command_FieldId_flag: { // bool: no argument required but value may be specified as aflag:Y
12337 *out_anon = false;
12338 retval=0;
12339 out_dflt="Y";
12340 } break;
12341 case command_FieldId_dstr: { // bool: no argument required but value may be specified as flag:Y
12342 *out_anon = false;
12343 } break;
12344 case command_FieldId_dnum: { // bool: no argument required but value may be specified as flag:Y
12345 *out_anon = false;
12346 } break;
12347 case command_FieldId_ddbl: { // bool: no argument required but value may be specified as flag:Y
12348 *out_anon = false;
12349 } break;
12350 case command_FieldId_dflag: { // bool: no argument required but value may be specified as flag:Y
12351 *out_anon = false;
12352 retval=0;
12353 out_dflt="Y";
12354 } break;
12355 case command_FieldId_mstr: { // bool: no argument required but value may be specified as dflag:Y
12356 *out_anon = false;
12357 } break;
12358 case command_FieldId_mnum: { // bool: no argument required but value may be specified as dflag:Y
12359 *out_anon = false;
12360 } break;
12361 case command_FieldId_mdbl: { // bool: no argument required but value may be specified as dflag:Y
12362 *out_anon = false;
12363 } break;
12364 case command_FieldId_amnum: { // bool: no argument required but value may be specified as dflag:Y
12365 *out_anon = true;
12366 } break;
12367 case command_FieldId_fconst: { // bool: no argument required but value may be specified as dflag:Y
12368 *out_anon = false;
12369 } break;
12370 case command_FieldId_cconst: { // bool: no argument required but value may be specified as dflag:Y
12371 *out_anon = false;
12372 } break;
12373 case command_FieldId_dregx: { // bool: no argument required but value may be specified as dflag:Y
12374 *out_anon = false;
12375 } break;
12376 case command_FieldId_dpkey: { // bool: no argument required but value may be specified as dflag:Y
12377 *out_anon = false;
12378 } break;
12379 default:
12380 retval=-1; // unrecognized
12381 }
12382 return retval;
12383}
12384
12385// --- command.atf_cmdline_proc.atf_cmdline.Start
12386// Start subprocess
12387// If subprocess already running, do nothing. Otherwise, start it
12388int command::atf_cmdline_Start(command::atf_cmdline_proc& parent) {
12389 int retval = 0;
12390 if (parent.pid == 0) {
12391 verblog(atf_cmdline_ToCmdline(parent)); // maybe print command
12392#ifdef WIN32
12393 algo_lib::ResolveExecFname(parent.path);
12394 tempstr cmdline(atf_cmdline_ToCmdline(parent));
12395 parent.pid = dospawn(Zeroterm(parent.path),Zeroterm(cmdline),parent.timeout,parent.fstdin,parent.fstdout,parent.fstderr);
12396#else
12397 parent.pid = fork();
12398 if (parent.pid == 0) { // child
12399 algo_lib::DieWithParent();
12400 if (parent.timeout > 0) {
12401 alarm(parent.timeout);
12402 }
12403 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstdin , 0);
12404 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstdout, 1);
12405 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstderr, 2);
12406 if (retval==0) retval= atf_cmdline_Execv(parent);
12407 if (retval != 0) { // if start fails, print error
12408 int err=errno;
12409 prerr("command.atf_cmdline_execv"
12410 <<Keyval("errno",err)
12411 <<Keyval("errstr",strerror(err))
12412 <<Keyval("comment","Execv failed"));
12413 }
12414 _exit(127); // if failed to start, exit anyway
12415 } else if (parent.pid == -1) {
12416 retval = errno; // failed to fork
12417 }
12418#endif
12419 }
12420 parent.status = parent.pid > 0 ? 0 : -1; // if didn't start, set error status
12421 return retval;
12422}
12423
12424// --- command.atf_cmdline_proc.atf_cmdline.StartRead
12425// Start subprocess & Read output
12426algo::Fildes command::atf_cmdline_StartRead(command::atf_cmdline_proc& parent, algo_lib::FFildes &read) {
12427 int pipefd[2];
12428 int rc=pipe(pipefd);
12429 (void)rc;
12430 read.fd.value = pipefd[0];
12431 parent.fstdout << ">&" << pipefd[1];
12432 atf_cmdline_Start(parent);
12433 (void)close(pipefd[1]);
12434 return read.fd;
12435}
12436
12437// --- command.atf_cmdline_proc.atf_cmdline.Kill
12438// Kill subprocess and wait
12439void command::atf_cmdline_Kill(command::atf_cmdline_proc& parent) {
12440 if (parent.pid != 0) {
12441 kill(parent.pid,9);
12442 atf_cmdline_Wait(parent);
12443 }
12444}
12445
12446// --- command.atf_cmdline_proc.atf_cmdline.Wait
12447// Wait for subprocess to return
12448void command::atf_cmdline_Wait(command::atf_cmdline_proc& parent) {
12449 if (parent.pid > 0) {
12450 int wait_flags = 0;
12451 int wait_status = 0;
12452 int rc = -1;
12453 do {
12454 // really wait for subprocess to exit
12455 rc = waitpid(parent.pid,&wait_status,wait_flags);
12456 } while (rc==-1 && errno==EINTR);
12457 if (rc == parent.pid) {
12458 parent.status = wait_status;
12459 parent.pid = 0;
12460 }
12461 }
12462}
12463
12464// --- command.atf_cmdline_proc.atf_cmdline.Exec
12465// Start + Wait
12466// Execute subprocess and return exit code
12467int command::atf_cmdline_Exec(command::atf_cmdline_proc& parent) {
12468 atf_cmdline_Start(parent);
12469 atf_cmdline_Wait(parent);
12470 return parent.status;
12471}
12472
12473// --- command.atf_cmdline_proc.atf_cmdline.ExecX
12474// Start + Wait, throw exception on error
12475// Execute subprocess; throw human-readable exception on error
12476void command::atf_cmdline_ExecX(command::atf_cmdline_proc& parent) {
12477 int rc = atf_cmdline_Exec(parent);
12478 vrfy(rc==0, tempstr() << "algo_lib.exec" << Keyval("cmd",atf_cmdline_ToCmdline(parent))
12479 << Keyval("comment",algo::DescribeWaitStatus(parent.status)));
12480}
12481
12482// --- command.atf_cmdline_proc.atf_cmdline.Execv
12483// Call execv()
12484// Call execv with specified parameters
12485int command::atf_cmdline_Execv(command::atf_cmdline_proc& parent) {
12486 int ret = 0;
12487 algo::StringAry args;
12488 atf_cmdline_ToArgv(parent, args);
12489 char **argv = (char**)alloca((ary_N(args)+1)*sizeof(*argv));
12490 ind_beg(algo::StringAry_ary_curs,arg,args) {
12491 argv[ind_curs(arg).index] = Zeroterm(arg);
12492 }ind_end;
12493 argv[ary_N(args)] = NULL;
12494 // if parent.path is relative, search for it in PATH
12495 algo_lib::ResolveExecFname(parent.path);
12496 ret = execv(Zeroterm(parent.path),argv);
12497 return ret;
12498}
12499
12500// --- command.atf_cmdline_proc.atf_cmdline.ToCmdline
12501algo::tempstr command::atf_cmdline_ToCmdline(command::atf_cmdline_proc& parent) {
12502 algo::tempstr retval;
12503 retval << parent.path << " ";
12504 command::atf_cmdline_PrintArgv(parent.cmd,retval);
12505 if (ch_N(parent.fstdin)) {
12506 retval << " " << parent.fstdin;
12507 }
12508 if (ch_N(parent.fstdout)) {
12509 retval << " " << parent.fstdout;
12510 }
12511 if (ch_N(parent.fstderr)) {
12512 retval << " 2" << parent.fstderr;
12513 }
12514 return retval;
12515}
12516
12517// --- command.atf_cmdline_proc.atf_cmdline.ToArgv
12518// Form array from the command line
12519void command::atf_cmdline_ToArgv(command::atf_cmdline_proc& parent, algo::StringAry& args) {
12520 ary_RemoveAll(args);
12521 ary_Alloc(args) << parent.path;
12522
12523 if (parent.cmd.in != "data") {
12524 cstring *arg = &ary_Alloc(args);
12525 *arg << "-in:";
12526 cstring_Print(parent.cmd.in, *arg);
12527 }
12528
12529 if (parent.cmd.exec != false) {
12530 cstring *arg = &ary_Alloc(args);
12531 *arg << "-exec:";
12532 bool_Print(parent.cmd.exec, *arg);
12533 }
12534
12535 if (true) {
12536 cstring *arg = &ary_Alloc(args);
12537 *arg << "-astr:";
12538 cstring_Print(parent.cmd.astr, *arg);
12539 }
12540
12541 if (parent.cmd.anum != 0) {
12542 cstring *arg = &ary_Alloc(args);
12543 *arg << "-anum:";
12544 i32_Print(parent.cmd.anum, *arg);
12545 }
12546
12547 if (parent.cmd.adbl != 0.0) {
12548 cstring *arg = &ary_Alloc(args);
12549 *arg << "-adbl:";
12550 double_Print(parent.cmd.adbl, *arg);
12551 }
12552
12553 if (parent.cmd.aflag != false) {
12554 cstring *arg = &ary_Alloc(args);
12555 *arg << "-aflag:";
12556 bool_Print(parent.cmd.aflag, *arg);
12557 }
12558
12559 if (true) {
12560 cstring *arg = &ary_Alloc(args);
12561 *arg << "-str:";
12562 cstring_Print(parent.cmd.str, *arg);
12563 }
12564
12565 if (parent.cmd.num != 0) {
12566 cstring *arg = &ary_Alloc(args);
12567 *arg << "-num:";
12568 i32_Print(parent.cmd.num, *arg);
12569 }
12570
12571 if (parent.cmd.dbl != 0.0) {
12572 cstring *arg = &ary_Alloc(args);
12573 *arg << "-dbl:";
12574 double_Print(parent.cmd.dbl, *arg);
12575 }
12576
12577 if (parent.cmd.flag != false) {
12578 cstring *arg = &ary_Alloc(args);
12579 *arg << "-flag:";
12580 bool_Print(parent.cmd.flag, *arg);
12581 }
12582
12583 if (parent.cmd.dstr != "blah") {
12584 cstring *arg = &ary_Alloc(args);
12585 *arg << "-dstr:";
12586 cstring_Print(parent.cmd.dstr, *arg);
12587 }
12588
12589 if (parent.cmd.dnum != -33) {
12590 cstring *arg = &ary_Alloc(args);
12591 *arg << "-dnum:";
12592 i32_Print(parent.cmd.dnum, *arg);
12593 }
12594
12595 if (parent.cmd.ddbl != 0.0001) {
12596 cstring *arg = &ary_Alloc(args);
12597 *arg << "-ddbl:";
12598 double_Print(parent.cmd.ddbl, *arg);
12599 }
12600
12601 if (parent.cmd.dflag != true) {
12602 cstring *arg = &ary_Alloc(args);
12603 *arg << "-dflag:";
12604 bool_Print(parent.cmd.dflag, *arg);
12605 }
12606 ind_beg(command::atf_cmdline_mstr_curs,value,parent.cmd) {
12607 cstring *arg = &ary_Alloc(args);
12608 *arg << "-mstr:";
12609 cstring_Print(value, *arg);
12610 }ind_end;
12611 ind_beg(command::atf_cmdline_mnum_curs,value,parent.cmd) {
12612 cstring *arg = &ary_Alloc(args);
12613 *arg << "-mnum:";
12614 i32_Print(value, *arg);
12615 }ind_end;
12616 ind_beg(command::atf_cmdline_mdbl_curs,value,parent.cmd) {
12617 cstring *arg = &ary_Alloc(args);
12618 *arg << "-mdbl:";
12619 double_Print(value, *arg);
12620 }ind_end;
12621 ind_beg(command::atf_cmdline_amnum_curs,value,parent.cmd) {
12622 cstring *arg = &ary_Alloc(args);
12623 *arg << "-amnum:";
12624 i32_Print(value, *arg);
12625 }ind_end;
12626
12627 if (parent.cmd.fconst != 0) {
12628 cstring *arg = &ary_Alloc(args);
12629 *arg << "-fconst:";
12630 command::fconst_Print(parent.cmd, *arg);
12631 }
12632
12633 if (true) {
12634 cstring *arg = &ary_Alloc(args);
12635 *arg << "-cconst:";
12636 Month_Print(parent.cmd.cconst, *arg);
12637 }
12638
12639 if (parent.cmd.dregx.expr != "%") {
12640 cstring *arg = &ary_Alloc(args);
12641 *arg << "-dregx:";
12642 command::dregx_Print(parent.cmd, *arg);
12643 }
12644
12645 if (parent.cmd.dpkey != "") {
12646 cstring *arg = &ary_Alloc(args);
12647 *arg << "-dpkey:";
12648 Smallstr100_Print(parent.cmd.dpkey, *arg);
12649 }
12650 for (int i=1; i < algo_lib::_db.cmdline.verbose; ++i) {
12651 ary_Alloc(args) << "-verbose";
12652 }
12653}
12654
12655// --- command.atf_cmdline_proc..Uninit
12656void command::atf_cmdline_proc_Uninit(command::atf_cmdline_proc& parent) {
12657 command::atf_cmdline_proc &row = parent; (void)row;
12658
12659 // command.atf_cmdline_proc.atf_cmdline.Uninit (Exec) //
12660 atf_cmdline_Kill(parent); // kill child, ensure forward progress
12661}
12662
12663// --- command.atf_comp.comptest.Print
12664// Print back to string
12665void command::comptest_Print(command::atf_comp& parent, algo::cstring &out) {
12666 Regx_Print(parent.comptest, out);
12667}
12668
12669// --- command.atf_comp.comptest.ReadStrptrMaybe
12670// Read Regx from string
12671// Convert string to field. Return success value
12672bool command::comptest_ReadStrptrMaybe(command::atf_comp& parent, algo::strptr in) {
12673 bool retval = true;
12674 Regx_ReadSql(parent.comptest, in, true);
12675 return retval;
12676}
12677
12678// --- command.atf_comp..ReadFieldMaybe
12679bool command::atf_comp_ReadFieldMaybe(command::atf_comp& parent, algo::strptr field, algo::strptr strval) {
12680 bool retval = true;
12681 command::FieldId field_id;
12682 (void)value_SetStrptrMaybe(field_id,field);
12683 switch(field_id) {
12684 case command_FieldId_in: {
12685 retval = algo::cstring_ReadStrptrMaybe(parent.in, strval);
12686 break;
12687 }
12688 case command_FieldId_comptest: {
12689 retval = comptest_ReadStrptrMaybe(parent, strval);
12690 break;
12691 }
12692 case command_FieldId_mdbg: {
12693 retval = bool_ReadStrptrMaybe(parent.mdbg, strval);
12694 break;
12695 }
12696 case command_FieldId_run: {
12697 retval = bool_ReadStrptrMaybe(parent.run, strval);
12698 break;
12699 }
12700 case command_FieldId_capture: {
12701 retval = bool_ReadStrptrMaybe(parent.capture, strval);
12702 break;
12703 }
12704 case command_FieldId_print: {
12705 retval = bool_ReadStrptrMaybe(parent.print, strval);
12706 break;
12707 }
12708 case command_FieldId_printinput: {
12709 retval = bool_ReadStrptrMaybe(parent.printinput, strval);
12710 break;
12711 }
12712 case command_FieldId_e: {
12713 retval = bool_ReadStrptrMaybe(parent.e, strval);
12714 break;
12715 }
12716 case command_FieldId_normalize: {
12717 retval = bool_ReadStrptrMaybe(parent.normalize, strval);
12718 break;
12719 }
12720 case command_FieldId_covcapture: {
12721 retval = bool_ReadStrptrMaybe(parent.covcapture, strval);
12722 break;
12723 }
12724 case command_FieldId_covcheck: {
12725 retval = bool_ReadStrptrMaybe(parent.covcheck, strval);
12726 break;
12727 }
12728 case command_FieldId_compdir: {
12729 retval = algo::cstring_ReadStrptrMaybe(parent.compdir, strval);
12730 break;
12731 }
12732 case command_FieldId_cfg: {
12733 retval = algo::Smallstr50_ReadStrptrMaybe(parent.cfg, strval);
12734 break;
12735 }
12736 case command_FieldId_check_untracked: {
12737 retval = bool_ReadStrptrMaybe(parent.check_untracked, strval);
12738 break;
12739 }
12740 case command_FieldId_maxerr: {
12741 retval = i32_ReadStrptrMaybe(parent.maxerr, strval);
12742 break;
12743 }
12744 case command_FieldId_build: {
12745 retval = bool_ReadStrptrMaybe(parent.build, strval);
12746 break;
12747 }
12748 case command_FieldId_ood: {
12749 retval = bool_ReadStrptrMaybe(parent.ood, strval);
12750 break;
12751 }
12752 case command_FieldId_memcheck: {
12753 retval = bool_ReadStrptrMaybe(parent.memcheck, strval);
12754 break;
12755 }
12756 case command_FieldId_force: {
12757 retval = bool_ReadStrptrMaybe(parent.force, strval);
12758 break;
12759 }
12760 case command_FieldId_callgrind: {
12761 retval = bool_ReadStrptrMaybe(parent.callgrind, strval);
12762 break;
12763 }
12764 case command_FieldId_maxjobs: {
12765 retval = i32_ReadStrptrMaybe(parent.maxjobs, strval);
12766 break;
12767 }
12768 case command_FieldId_stream: {
12769 retval = bool_ReadStrptrMaybe(parent.stream, strval);
12770 break;
12771 }
12772 case command_FieldId_i: {
12773 retval = bool_ReadStrptrMaybe(parent.i, strval);
12774 break;
12775 }
12776 case command_FieldId_write: {
12777 retval = bool_ReadStrptrMaybe(parent.write, strval);
12778 break;
12779 }
12780 case command_FieldId_report: {
12781 retval = bool_ReadStrptrMaybe(parent.report, strval);
12782 break;
12783 }
12784 case command_FieldId_b: {
12785 retval = algo::cstring_ReadStrptrMaybe(parent.b, strval);
12786 break;
12787 }
12788 default: break;
12789 }
12790 if (!retval) {
12791 algo_lib::AppendErrtext("attr",field);
12792 }
12793 return retval;
12794}
12795
12796// --- command.atf_comp..ReadTupleMaybe
12797// Read fields of command::atf_comp from attributes of ascii tuple TUPLE
12798bool command::atf_comp_ReadTupleMaybe(command::atf_comp &parent, algo::Tuple &tuple) {
12799 bool retval = true;
12800 int anon_idx = 0;
12801 ind_beg(algo::Tuple_attrs_curs,attr,tuple) {
12802 if (ch_N(attr.name) == 0) {
12803 attr.name = atf_comp_GetAnon(parent, anon_idx++);
12804 }
12805 retval = atf_comp_ReadFieldMaybe(parent, attr.name, attr.value);
12806 if (!retval) {
12807 break;
12808 }
12809 }ind_end;
12810 return retval;
12811}
12812
12813// --- command.atf_comp..Init
12814// Set all fields to initial values.
12815void command::atf_comp_Init(command::atf_comp& parent) {
12816 parent.in = algo::strptr("data");
12817 Regx_ReadSql(parent.comptest, "%", true);
12818 parent.mdbg = bool(false);
12819 parent.run = bool(true);
12820 parent.capture = bool(false);
12821 parent.print = bool(false);
12822 parent.printinput = bool(false);
12823 parent.e = bool(false);
12824 parent.normalize = bool(false);
12825 parent.covcapture = bool(false);
12826 parent.covcheck = bool(false);
12827 parent.compdir = algo::strptr("");
12828 parent.cfg = algo::strptr("release");
12829 parent.check_untracked = bool(true);
12830 parent.maxerr = i32(1);
12831 parent.build = bool(false);
12832 parent.ood = bool(false);
12833 parent.memcheck = bool(false);
12834 parent.force = bool(false);
12835 parent.callgrind = bool(false);
12836 parent.maxjobs = i32(0);
12837 parent.stream = bool(false);
12838 parent.i = bool(false);
12839 parent.write = bool(true);
12840 parent.report = bool(false);
12841 parent.b = algo::strptr("");
12842}
12843
12844// --- command.atf_comp..ToCmdline
12845// Convenience function that returns a full command line
12846// Assume command is in a directory called bin
12847tempstr command::atf_comp_ToCmdline(command::atf_comp& row) {
12848 tempstr ret;
12849 ret << "bin/atf_comp ";
12850 atf_comp_PrintArgv(row, ret);
12851 // inherit less intense verbose, debug options
12852 for (int i = 1; i < algo_lib::_db.cmdline.verbose; i++) {
12853 ret << " -verbose";
12854 }
12855 for (int i = 1; i < algo_lib::_db.cmdline.debug; i++) {
12856 ret << " -debug";
12857 }
12858 return ret;
12859}
12860
12861// --- command.atf_comp..PrintArgv
12862// print string representation of ROW to string STR
12863// cfmt:command.atf_comp.Argv printfmt:Tuple
12864void command::atf_comp_PrintArgv(command::atf_comp& row, algo::cstring& str) {
12865 algo::tempstr temp;
12866 (void)temp;
12867 (void)str;
12868 if (!(row.in == "data")) {
12869 ch_RemoveAll(temp);
12870 cstring_Print(row.in, temp);
12871 str << " -in:";
12872 strptr_PrintBash(temp,str);
12873 }
12874 ch_RemoveAll(temp);
12875 command::comptest_Print(const_cast<command::atf_comp&>(row), temp);
12876 str << " -comptest:";
12877 strptr_PrintBash(temp,str);
12878 if (!(row.mdbg == false)) {
12879 ch_RemoveAll(temp);
12880 bool_Print(row.mdbg, temp);
12881 str << " -mdbg:";
12882 strptr_PrintBash(temp,str);
12883 }
12884 if (!(row.run == true)) {
12885 ch_RemoveAll(temp);
12886 bool_Print(row.run, temp);
12887 str << " -run:";
12888 strptr_PrintBash(temp,str);
12889 }
12890 if (!(row.capture == false)) {
12891 ch_RemoveAll(temp);
12892 bool_Print(row.capture, temp);
12893 str << " -capture:";
12894 strptr_PrintBash(temp,str);
12895 }
12896 if (!(row.print == false)) {
12897 ch_RemoveAll(temp);
12898 bool_Print(row.print, temp);
12899 str << " -print:";
12900 strptr_PrintBash(temp,str);
12901 }
12902 if (!(row.printinput == false)) {
12903 ch_RemoveAll(temp);
12904 bool_Print(row.printinput, temp);
12905 str << " -printinput:";
12906 strptr_PrintBash(temp,str);
12907 }
12908 if (!(row.e == false)) {
12909 ch_RemoveAll(temp);
12910 bool_Print(row.e, temp);
12911 str << " -e:";
12912 strptr_PrintBash(temp,str);
12913 }
12914 if (!(row.normalize == false)) {
12915 ch_RemoveAll(temp);
12916 bool_Print(row.normalize, temp);
12917 str << " -normalize:";
12918 strptr_PrintBash(temp,str);
12919 }
12920 if (!(row.covcapture == false)) {
12921 ch_RemoveAll(temp);
12922 bool_Print(row.covcapture, temp);
12923 str << " -covcapture:";
12924 strptr_PrintBash(temp,str);
12925 }
12926 if (!(row.covcheck == false)) {
12927 ch_RemoveAll(temp);
12928 bool_Print(row.covcheck, temp);
12929 str << " -covcheck:";
12930 strptr_PrintBash(temp,str);
12931 }
12932 if (!(row.compdir == "")) {
12933 ch_RemoveAll(temp);
12934 cstring_Print(row.compdir, temp);
12935 str << " -compdir:";
12936 strptr_PrintBash(temp,str);
12937 }
12938 if (!(row.cfg == "release")) {
12939 ch_RemoveAll(temp);
12940 Smallstr50_Print(row.cfg, temp);
12941 str << " -cfg:";
12942 strptr_PrintBash(temp,str);
12943 }
12944 if (!(row.check_untracked == true)) {
12945 ch_RemoveAll(temp);
12946 bool_Print(row.check_untracked, temp);
12947 str << " -check_untracked:";
12948 strptr_PrintBash(temp,str);
12949 }
12950 if (!(row.maxerr == 1)) {
12951 ch_RemoveAll(temp);
12952 i32_Print(row.maxerr, temp);
12953 str << " -maxerr:";
12954 strptr_PrintBash(temp,str);
12955 }
12956 if (!(row.build == false)) {
12957 ch_RemoveAll(temp);
12958 bool_Print(row.build, temp);
12959 str << " -build:";
12960 strptr_PrintBash(temp,str);
12961 }
12962 if (!(row.ood == false)) {
12963 ch_RemoveAll(temp);
12964 bool_Print(row.ood, temp);
12965 str << " -ood:";
12966 strptr_PrintBash(temp,str);
12967 }
12968 if (!(row.memcheck == false)) {
12969 ch_RemoveAll(temp);
12970 bool_Print(row.memcheck, temp);
12971 str << " -memcheck:";
12972 strptr_PrintBash(temp,str);
12973 }
12974 if (!(row.force == false)) {
12975 ch_RemoveAll(temp);
12976 bool_Print(row.force, temp);
12977 str << " -force:";
12978 strptr_PrintBash(temp,str);
12979 }
12980 if (!(row.callgrind == false)) {
12981 ch_RemoveAll(temp);
12982 bool_Print(row.callgrind, temp);
12983 str << " -callgrind:";
12984 strptr_PrintBash(temp,str);
12985 }
12986 if (!(row.maxjobs == 0)) {
12987 ch_RemoveAll(temp);
12988 i32_Print(row.maxjobs, temp);
12989 str << " -maxjobs:";
12990 strptr_PrintBash(temp,str);
12991 }
12992 if (!(row.stream == false)) {
12993 ch_RemoveAll(temp);
12994 bool_Print(row.stream, temp);
12995 str << " -stream:";
12996 strptr_PrintBash(temp,str);
12997 }
12998 if (!(row.i == false)) {
12999 ch_RemoveAll(temp);
13000 bool_Print(row.i, temp);
13001 str << " -i:";
13002 strptr_PrintBash(temp,str);
13003 }
13004 if (!(row.write == true)) {
13005 ch_RemoveAll(temp);
13006 bool_Print(row.write, temp);
13007 str << " -write:";
13008 strptr_PrintBash(temp,str);
13009 }
13010 if (!(row.report == false)) {
13011 ch_RemoveAll(temp);
13012 bool_Print(row.report, temp);
13013 str << " -report:";
13014 strptr_PrintBash(temp,str);
13015 }
13016 if (!(row.b == "")) {
13017 ch_RemoveAll(temp);
13018 cstring_Print(row.b, temp);
13019 str << " -b:";
13020 strptr_PrintBash(temp,str);
13021 }
13022}
13023
13024// --- command.atf_comp..GetAnon
13025algo::strptr command::atf_comp_GetAnon(command::atf_comp &parent, i32 idx) {
13026 (void)parent;//only to avoid -Wunused-parameter
13027 switch(idx) {
13028 case(0): return strptr("comptest", 8);
13029 default: return algo::strptr();
13030 }
13031}
13032
13033// --- command.atf_comp..NArgs
13034// Used with command lines
13035// Return # of command-line arguments that must follow this argument
13036// If FIELD is invalid, return -1
13037i32 command::atf_comp_NArgs(command::FieldId field, algo::strptr& out_dflt, bool* out_anon) {
13038 i32 retval = 1;
13039 switch (field) {
13040 case command_FieldId_in: { // $comment
13041 *out_anon = false;
13042 } break;
13043 case command_FieldId_comptest: { // $comment
13044 *out_anon = true;
13045 } break;
13046 case command_FieldId_mdbg: { // $comment
13047 *out_anon = false;
13048 retval=0;
13049 out_dflt="Y";
13050 } break;
13051 case command_FieldId_run: { // bool: no argument required but value may be specified as mdbg:Y
13052 *out_anon = false;
13053 retval=0;
13054 out_dflt="Y";
13055 } break;
13056 case command_FieldId_capture: { // bool: no argument required but value may be specified as run:Y
13057 *out_anon = false;
13058 retval=0;
13059 out_dflt="Y";
13060 } break;
13061 case command_FieldId_print: { // bool: no argument required but value may be specified as capture:Y
13062 *out_anon = false;
13063 retval=0;
13064 out_dflt="Y";
13065 } break;
13066 case command_FieldId_printinput: { // bool: no argument required but value may be specified as print:Y
13067 *out_anon = false;
13068 retval=0;
13069 out_dflt="Y";
13070 } break;
13071 case command_FieldId_e: { // bool: no argument required but value may be specified as printinput:Y
13072 *out_anon = false;
13073 retval=0;
13074 out_dflt="Y";
13075 } break;
13076 case command_FieldId_normalize: { // bool: no argument required but value may be specified as e:Y
13077 *out_anon = false;
13078 retval=0;
13079 out_dflt="Y";
13080 } break;
13081 case command_FieldId_covcapture: { // bool: no argument required but value may be specified as normalize:Y
13082 *out_anon = false;
13083 retval=0;
13084 out_dflt="Y";
13085 } break;
13086 case command_FieldId_covcheck: { // bool: no argument required but value may be specified as covcapture:Y
13087 *out_anon = false;
13088 retval=0;
13089 out_dflt="Y";
13090 } break;
13091 case command_FieldId_compdir: { // bool: no argument required but value may be specified as covcheck:Y
13092 *out_anon = false;
13093 } break;
13094 case command_FieldId_cfg: { // bool: no argument required but value may be specified as covcheck:Y
13095 *out_anon = false;
13096 } break;
13097 case command_FieldId_check_untracked: { // bool: no argument required but value may be specified as covcheck:Y
13098 *out_anon = false;
13099 retval=0;
13100 out_dflt="Y";
13101 } break;
13102 case command_FieldId_maxerr: { // bool: no argument required but value may be specified as check_untracked:Y
13103 *out_anon = false;
13104 } break;
13105 case command_FieldId_build: { // bool: no argument required but value may be specified as check_untracked:Y
13106 *out_anon = false;
13107 retval=0;
13108 out_dflt="Y";
13109 } break;
13110 case command_FieldId_ood: { // bool: no argument required but value may be specified as build:Y
13111 *out_anon = false;
13112 retval=0;
13113 out_dflt="Y";
13114 } break;
13115 case command_FieldId_memcheck: { // bool: no argument required but value may be specified as ood:Y
13116 *out_anon = false;
13117 retval=0;
13118 out_dflt="Y";
13119 } break;
13120 case command_FieldId_force: { // bool: no argument required but value may be specified as memcheck:Y
13121 *out_anon = false;
13122 retval=0;
13123 out_dflt="Y";
13124 } break;
13125 case command_FieldId_callgrind: { // bool: no argument required but value may be specified as force:Y
13126 *out_anon = false;
13127 retval=0;
13128 out_dflt="Y";
13129 } break;
13130 case command_FieldId_maxjobs: { // bool: no argument required but value may be specified as callgrind:Y
13131 *out_anon = false;
13132 } break;
13133 case command_FieldId_stream: { // bool: no argument required but value may be specified as callgrind:Y
13134 *out_anon = false;
13135 retval=0;
13136 out_dflt="Y";
13137 } break;
13138 case command_FieldId_i: { // bool: no argument required but value may be specified as stream:Y
13139 *out_anon = false;
13140 retval=0;
13141 out_dflt="Y";
13142 } break;
13143 case command_FieldId_write: { // bool: no argument required but value may be specified as i:Y
13144 *out_anon = false;
13145 retval=0;
13146 out_dflt="Y";
13147 } break;
13148 case command_FieldId_report: { // bool: no argument required but value may be specified as write:Y
13149 *out_anon = false;
13150 retval=0;
13151 out_dflt="Y";
13152 } break;
13153 case command_FieldId_b: { // bool: no argument required but value may be specified as report:Y
13154 *out_anon = false;
13155 } break;
13156 default:
13157 retval=-1; // unrecognized
13158 }
13159 return retval;
13160}
13161
13162// --- command.atf_comp_proc.atf_comp.Start
13163// Start subprocess
13164// If subprocess already running, do nothing. Otherwise, start it
13165int command::atf_comp_Start(command::atf_comp_proc& parent) {
13166 int retval = 0;
13167 if (parent.pid == 0) {
13168 verblog(atf_comp_ToCmdline(parent)); // maybe print command
13169#ifdef WIN32
13170 algo_lib::ResolveExecFname(parent.path);
13171 tempstr cmdline(atf_comp_ToCmdline(parent));
13172 parent.pid = dospawn(Zeroterm(parent.path),Zeroterm(cmdline),parent.timeout,parent.fstdin,parent.fstdout,parent.fstderr);
13173#else
13174 parent.pid = fork();
13175 if (parent.pid == 0) { // child
13176 algo_lib::DieWithParent();
13177 if (parent.timeout > 0) {
13178 alarm(parent.timeout);
13179 }
13180 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstdin , 0);
13181 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstdout, 1);
13182 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstderr, 2);
13183 if (retval==0) retval= atf_comp_Execv(parent);
13184 if (retval != 0) { // if start fails, print error
13185 int err=errno;
13186 prerr("command.atf_comp_execv"
13187 <<Keyval("errno",err)
13188 <<Keyval("errstr",strerror(err))
13189 <<Keyval("comment","Execv failed"));
13190 }
13191 _exit(127); // if failed to start, exit anyway
13192 } else if (parent.pid == -1) {
13193 retval = errno; // failed to fork
13194 }
13195#endif
13196 }
13197 parent.status = parent.pid > 0 ? 0 : -1; // if didn't start, set error status
13198 return retval;
13199}
13200
13201// --- command.atf_comp_proc.atf_comp.StartRead
13202// Start subprocess & Read output
13203algo::Fildes command::atf_comp_StartRead(command::atf_comp_proc& parent, algo_lib::FFildes &read) {
13204 int pipefd[2];
13205 int rc=pipe(pipefd);
13206 (void)rc;
13207 read.fd.value = pipefd[0];
13208 parent.fstdout << ">&" << pipefd[1];
13209 atf_comp_Start(parent);
13210 (void)close(pipefd[1]);
13211 return read.fd;
13212}
13213
13214// --- command.atf_comp_proc.atf_comp.Kill
13215// Kill subprocess and wait
13216void command::atf_comp_Kill(command::atf_comp_proc& parent) {
13217 if (parent.pid != 0) {
13218 kill(parent.pid,9);
13219 atf_comp_Wait(parent);
13220 }
13221}
13222
13223// --- command.atf_comp_proc.atf_comp.Wait
13224// Wait for subprocess to return
13225void command::atf_comp_Wait(command::atf_comp_proc& parent) {
13226 if (parent.pid > 0) {
13227 int wait_flags = 0;
13228 int wait_status = 0;
13229 int rc = -1;
13230 do {
13231 // really wait for subprocess to exit
13232 rc = waitpid(parent.pid,&wait_status,wait_flags);
13233 } while (rc==-1 && errno==EINTR);
13234 if (rc == parent.pid) {
13235 parent.status = wait_status;
13236 parent.pid = 0;
13237 }
13238 }
13239}
13240
13241// --- command.atf_comp_proc.atf_comp.Exec
13242// Start + Wait
13243// Execute subprocess and return exit code
13244int command::atf_comp_Exec(command::atf_comp_proc& parent) {
13245 atf_comp_Start(parent);
13246 atf_comp_Wait(parent);
13247 return parent.status;
13248}
13249
13250// --- command.atf_comp_proc.atf_comp.ExecX
13251// Start + Wait, throw exception on error
13252// Execute subprocess; throw human-readable exception on error
13253void command::atf_comp_ExecX(command::atf_comp_proc& parent) {
13254 int rc = atf_comp_Exec(parent);
13255 vrfy(rc==0, tempstr() << "algo_lib.exec" << Keyval("cmd",atf_comp_ToCmdline(parent))
13256 << Keyval("comment",algo::DescribeWaitStatus(parent.status)));
13257}
13258
13259// --- command.atf_comp_proc.atf_comp.Execv
13260// Call execv()
13261// Call execv with specified parameters
13262int command::atf_comp_Execv(command::atf_comp_proc& parent) {
13263 int ret = 0;
13264 algo::StringAry args;
13265 atf_comp_ToArgv(parent, args);
13266 char **argv = (char**)alloca((ary_N(args)+1)*sizeof(*argv));
13267 ind_beg(algo::StringAry_ary_curs,arg,args) {
13268 argv[ind_curs(arg).index] = Zeroterm(arg);
13269 }ind_end;
13270 argv[ary_N(args)] = NULL;
13271 // if parent.path is relative, search for it in PATH
13272 algo_lib::ResolveExecFname(parent.path);
13273 ret = execv(Zeroterm(parent.path),argv);
13274 return ret;
13275}
13276
13277// --- command.atf_comp_proc.atf_comp.ToCmdline
13278algo::tempstr command::atf_comp_ToCmdline(command::atf_comp_proc& parent) {
13279 algo::tempstr retval;
13280 retval << parent.path << " ";
13281 command::atf_comp_PrintArgv(parent.cmd,retval);
13282 if (ch_N(parent.fstdin)) {
13283 retval << " " << parent.fstdin;
13284 }
13285 if (ch_N(parent.fstdout)) {
13286 retval << " " << parent.fstdout;
13287 }
13288 if (ch_N(parent.fstderr)) {
13289 retval << " 2" << parent.fstderr;
13290 }
13291 return retval;
13292}
13293
13294// --- command.atf_comp_proc.atf_comp.ToArgv
13295// Form array from the command line
13296void command::atf_comp_ToArgv(command::atf_comp_proc& parent, algo::StringAry& args) {
13297 ary_RemoveAll(args);
13298 ary_Alloc(args) << parent.path;
13299
13300 if (parent.cmd.in != "data") {
13301 cstring *arg = &ary_Alloc(args);
13302 *arg << "-in:";
13303 cstring_Print(parent.cmd.in, *arg);
13304 }
13305
13306 if (parent.cmd.comptest.expr != "%") {
13307 cstring *arg = &ary_Alloc(args);
13308 *arg << "-comptest:";
13309 command::comptest_Print(parent.cmd, *arg);
13310 }
13311
13312 if (parent.cmd.mdbg != false) {
13313 cstring *arg = &ary_Alloc(args);
13314 *arg << "-mdbg:";
13315 bool_Print(parent.cmd.mdbg, *arg);
13316 }
13317
13318 if (parent.cmd.run != true) {
13319 cstring *arg = &ary_Alloc(args);
13320 *arg << "-run:";
13321 bool_Print(parent.cmd.run, *arg);
13322 }
13323
13324 if (parent.cmd.capture != false) {
13325 cstring *arg = &ary_Alloc(args);
13326 *arg << "-capture:";
13327 bool_Print(parent.cmd.capture, *arg);
13328 }
13329
13330 if (parent.cmd.print != false) {
13331 cstring *arg = &ary_Alloc(args);
13332 *arg << "-print:";
13333 bool_Print(parent.cmd.print, *arg);
13334 }
13335
13336 if (parent.cmd.printinput != false) {
13337 cstring *arg = &ary_Alloc(args);
13338 *arg << "-printinput:";
13339 bool_Print(parent.cmd.printinput, *arg);
13340 }
13341
13342 if (parent.cmd.e != false) {
13343 cstring *arg = &ary_Alloc(args);
13344 *arg << "-e:";
13345 bool_Print(parent.cmd.e, *arg);
13346 }
13347
13348 if (parent.cmd.normalize != false) {
13349 cstring *arg = &ary_Alloc(args);
13350 *arg << "-normalize:";
13351 bool_Print(parent.cmd.normalize, *arg);
13352 }
13353
13354 if (parent.cmd.covcapture != false) {
13355 cstring *arg = &ary_Alloc(args);
13356 *arg << "-covcapture:";
13357 bool_Print(parent.cmd.covcapture, *arg);
13358 }
13359
13360 if (parent.cmd.covcheck != false) {
13361 cstring *arg = &ary_Alloc(args);
13362 *arg << "-covcheck:";
13363 bool_Print(parent.cmd.covcheck, *arg);
13364 }
13365
13366 if (parent.cmd.compdir != "") {
13367 cstring *arg = &ary_Alloc(args);
13368 *arg << "-compdir:";
13369 cstring_Print(parent.cmd.compdir, *arg);
13370 }
13371
13372 if (parent.cmd.cfg != "release") {
13373 cstring *arg = &ary_Alloc(args);
13374 *arg << "-cfg:";
13375 Smallstr50_Print(parent.cmd.cfg, *arg);
13376 }
13377
13378 if (parent.cmd.check_untracked != true) {
13379 cstring *arg = &ary_Alloc(args);
13380 *arg << "-check_untracked:";
13381 bool_Print(parent.cmd.check_untracked, *arg);
13382 }
13383
13384 if (parent.cmd.maxerr != 1) {
13385 cstring *arg = &ary_Alloc(args);
13386 *arg << "-maxerr:";
13387 i32_Print(parent.cmd.maxerr, *arg);
13388 }
13389
13390 if (parent.cmd.build != false) {
13391 cstring *arg = &ary_Alloc(args);
13392 *arg << "-build:";
13393 bool_Print(parent.cmd.build, *arg);
13394 }
13395
13396 if (parent.cmd.ood != false) {
13397 cstring *arg = &ary_Alloc(args);
13398 *arg << "-ood:";
13399 bool_Print(parent.cmd.ood, *arg);
13400 }
13401
13402 if (parent.cmd.memcheck != false) {
13403 cstring *arg = &ary_Alloc(args);
13404 *arg << "-memcheck:";
13405 bool_Print(parent.cmd.memcheck, *arg);
13406 }
13407
13408 if (parent.cmd.force != false) {
13409 cstring *arg = &ary_Alloc(args);
13410 *arg << "-force:";
13411 bool_Print(parent.cmd.force, *arg);
13412 }
13413
13414 if (parent.cmd.callgrind != false) {
13415 cstring *arg = &ary_Alloc(args);
13416 *arg << "-callgrind:";
13417 bool_Print(parent.cmd.callgrind, *arg);
13418 }
13419
13420 if (parent.cmd.maxjobs != 0) {
13421 cstring *arg = &ary_Alloc(args);
13422 *arg << "-maxjobs:";
13423 i32_Print(parent.cmd.maxjobs, *arg);
13424 }
13425
13426 if (parent.cmd.stream != false) {
13427 cstring *arg = &ary_Alloc(args);
13428 *arg << "-stream:";
13429 bool_Print(parent.cmd.stream, *arg);
13430 }
13431
13432 if (parent.cmd.i != false) {
13433 cstring *arg = &ary_Alloc(args);
13434 *arg << "-i:";
13435 bool_Print(parent.cmd.i, *arg);
13436 }
13437
13438 if (parent.cmd.write != true) {
13439 cstring *arg = &ary_Alloc(args);
13440 *arg << "-write:";
13441 bool_Print(parent.cmd.write, *arg);
13442 }
13443
13444 if (parent.cmd.report != false) {
13445 cstring *arg = &ary_Alloc(args);
13446 *arg << "-report:";
13447 bool_Print(parent.cmd.report, *arg);
13448 }
13449
13450 if (parent.cmd.b != "") {
13451 cstring *arg = &ary_Alloc(args);
13452 *arg << "-b:";
13453 cstring_Print(parent.cmd.b, *arg);
13454 }
13455 for (int i=1; i < algo_lib::_db.cmdline.verbose; ++i) {
13456 ary_Alloc(args) << "-verbose";
13457 }
13458}
13459
13460// --- command.atf_comp_proc..Uninit
13461void command::atf_comp_proc_Uninit(command::atf_comp_proc& parent) {
13462 command::atf_comp_proc &row = parent; (void)row;
13463
13464 // command.atf_comp_proc.atf_comp.Uninit (Exec) //
13465 atf_comp_Kill(parent); // kill child, ensure forward progress
13466}
13467
13468// --- command.atf_cov.exclude.Print
13469// Print back to string
13470void command::exclude_Print(command::atf_cov& parent, algo::cstring &out) {
13471 Regx_Print(parent.exclude, out);
13472}
13473
13474// --- command.atf_cov.exclude.ReadStrptrMaybe
13475// Read Regx from string
13476// Convert string to field. Return success value
13477bool command::exclude_ReadStrptrMaybe(command::atf_cov& parent, algo::strptr in) {
13478 bool retval = true;
13479 Regx_ReadSql(parent.exclude, in, true);
13480 return retval;
13481}
13482
13483// --- command.atf_cov..ReadFieldMaybe
13484bool command::atf_cov_ReadFieldMaybe(command::atf_cov& parent, algo::strptr field, algo::strptr strval) {
13485 bool retval = true;
13486 command::FieldId field_id;
13487 (void)value_SetStrptrMaybe(field_id,field);
13488 switch(field_id) {
13489 case command_FieldId_in: {
13490 retval = algo::cstring_ReadStrptrMaybe(parent.in, strval);
13491 break;
13492 }
13493 case command_FieldId_covdir: {
13494 retval = algo::cstring_ReadStrptrMaybe(parent.covdir, strval);
13495 break;
13496 }
13497 case command_FieldId_logfile: {
13498 retval = algo::cstring_ReadStrptrMaybe(parent.logfile, strval);
13499 break;
13500 }
13501 case command_FieldId_runcmd: {
13502 retval = algo::cstring_ReadStrptrMaybe(parent.runcmd, strval);
13503 break;
13504 }
13505 case command_FieldId_exclude: {
13506 retval = exclude_ReadStrptrMaybe(parent, strval);
13507 break;
13508 }
13509 case command_FieldId_mergepath: {
13510 retval = algo::cstring_ReadStrptrMaybe(parent.mergepath, strval);
13511 break;
13512 }
13513 case command_FieldId_gcov: {
13514 retval = bool_ReadStrptrMaybe(parent.gcov, strval);
13515 break;
13516 }
13517 case command_FieldId_ssim: {
13518 retval = bool_ReadStrptrMaybe(parent.ssim, strval);
13519 break;
13520 }
13521 case command_FieldId_report: {
13522 retval = bool_ReadStrptrMaybe(parent.report, strval);
13523 break;
13524 }
13525 case command_FieldId_capture: {
13526 retval = bool_ReadStrptrMaybe(parent.capture, strval);
13527 break;
13528 }
13529 case command_FieldId_xmlpretty: {
13530 retval = bool_ReadStrptrMaybe(parent.xmlpretty, strval);
13531 break;
13532 }
13533 case command_FieldId_summary: {
13534 retval = bool_ReadStrptrMaybe(parent.summary, strval);
13535 break;
13536 }
13537 case command_FieldId_check: {
13538 retval = bool_ReadStrptrMaybe(parent.check, strval);
13539 break;
13540 }
13541 default: break;
13542 }
13543 if (!retval) {
13544 algo_lib::AppendErrtext("attr",field);
13545 }
13546 return retval;
13547}
13548
13549// --- command.atf_cov..ReadTupleMaybe
13550// Read fields of command::atf_cov from attributes of ascii tuple TUPLE
13551bool command::atf_cov_ReadTupleMaybe(command::atf_cov &parent, algo::Tuple &tuple) {
13552 bool retval = true;
13553 ind_beg(algo::Tuple_attrs_curs,attr,tuple) {
13554 retval = atf_cov_ReadFieldMaybe(parent, attr.name, attr.value);
13555 if (!retval) {
13556 break;
13557 }
13558 }ind_end;
13559 return retval;
13560}
13561
13562// --- command.atf_cov..Init
13563// Set all fields to initial values.
13564void command::atf_cov_Init(command::atf_cov& parent) {
13565 parent.in = algo::strptr("data");
13566 parent.covdir = algo::strptr("temp/covdata");
13567 parent.logfile = algo::strptr("");
13568 parent.runcmd = algo::strptr("");
13569 Regx_ReadSql(parent.exclude, "(extern|include/gen|cpp/gen)/%", true);
13570 parent.mergepath = algo::strptr("");
13571 parent.gcov = bool(false);
13572 parent.ssim = bool(false);
13573 parent.report = bool(false);
13574 parent.capture = bool(false);
13575 parent.xmlpretty = bool(false);
13576 parent.summary = bool(true);
13577 parent.check = bool(false);
13578}
13579
13580// --- command.atf_cov..ToCmdline
13581// Convenience function that returns a full command line
13582// Assume command is in a directory called bin
13583tempstr command::atf_cov_ToCmdline(command::atf_cov& row) {
13584 tempstr ret;
13585 ret << "bin/atf_cov ";
13586 atf_cov_PrintArgv(row, ret);
13587 // inherit less intense verbose, debug options
13588 for (int i = 1; i < algo_lib::_db.cmdline.verbose; i++) {
13589 ret << " -verbose";
13590 }
13591 for (int i = 1; i < algo_lib::_db.cmdline.debug; i++) {
13592 ret << " -debug";
13593 }
13594 return ret;
13595}
13596
13597// --- command.atf_cov..PrintArgv
13598// print string representation of ROW to string STR
13599// cfmt:command.atf_cov.Argv printfmt:Tuple
13600void command::atf_cov_PrintArgv(command::atf_cov& row, algo::cstring& str) {
13601 algo::tempstr temp;
13602 (void)temp;
13603 (void)str;
13604 if (!(row.in == "data")) {
13605 ch_RemoveAll(temp);
13606 cstring_Print(row.in, temp);
13607 str << " -in:";
13608 strptr_PrintBash(temp,str);
13609 }
13610 if (!(row.covdir == "temp/covdata")) {
13611 ch_RemoveAll(temp);
13612 cstring_Print(row.covdir, temp);
13613 str << " -covdir:";
13614 strptr_PrintBash(temp,str);
13615 }
13616 if (!(row.logfile == "")) {
13617 ch_RemoveAll(temp);
13618 cstring_Print(row.logfile, temp);
13619 str << " -logfile:";
13620 strptr_PrintBash(temp,str);
13621 }
13622 if (!(row.runcmd == "")) {
13623 ch_RemoveAll(temp);
13624 cstring_Print(row.runcmd, temp);
13625 str << " -runcmd:";
13626 strptr_PrintBash(temp,str);
13627 }
13628 if (!(row.exclude.expr == "(extern|include/gen|cpp/gen)/%")) {
13629 ch_RemoveAll(temp);
13630 command::exclude_Print(const_cast<command::atf_cov&>(row), temp);
13631 str << " -exclude:";
13632 strptr_PrintBash(temp,str);
13633 }
13634 if (!(row.mergepath == "")) {
13635 ch_RemoveAll(temp);
13636 cstring_Print(row.mergepath, temp);
13637 str << " -mergepath:";
13638 strptr_PrintBash(temp,str);
13639 }
13640 if (!(row.gcov == false)) {
13641 ch_RemoveAll(temp);
13642 bool_Print(row.gcov, temp);
13643 str << " -gcov:";
13644 strptr_PrintBash(temp,str);
13645 }
13646 if (!(row.ssim == false)) {
13647 ch_RemoveAll(temp);
13648 bool_Print(row.ssim, temp);
13649 str << " -ssim:";
13650 strptr_PrintBash(temp,str);
13651 }
13652 if (!(row.report == false)) {
13653 ch_RemoveAll(temp);
13654 bool_Print(row.report, temp);
13655 str << " -report:";
13656 strptr_PrintBash(temp,str);
13657 }
13658 if (!(row.capture == false)) {
13659 ch_RemoveAll(temp);
13660 bool_Print(row.capture, temp);
13661 str << " -capture:";
13662 strptr_PrintBash(temp,str);
13663 }
13664 if (!(row.xmlpretty == false)) {
13665 ch_RemoveAll(temp);
13666 bool_Print(row.xmlpretty, temp);
13667 str << " -xmlpretty:";
13668 strptr_PrintBash(temp,str);
13669 }
13670 if (!(row.summary == true)) {
13671 ch_RemoveAll(temp);
13672 bool_Print(row.summary, temp);
13673 str << " -summary:";
13674 strptr_PrintBash(temp,str);
13675 }
13676 if (!(row.check == false)) {
13677 ch_RemoveAll(temp);
13678 bool_Print(row.check, temp);
13679 str << " -check:";
13680 strptr_PrintBash(temp,str);
13681 }
13682}
13683
13684// --- command.atf_cov..NArgs
13685// Used with command lines
13686// Return # of command-line arguments that must follow this argument
13687// If FIELD is invalid, return -1
13688i32 command::atf_cov_NArgs(command::FieldId field, algo::strptr& out_dflt, bool* out_anon) {
13689 i32 retval = 1;
13690 switch (field) {
13691 case command_FieldId_in: { // $comment
13692 *out_anon = false;
13693 } break;
13694 case command_FieldId_covdir: { // $comment
13695 *out_anon = false;
13696 } break;
13697 case command_FieldId_logfile: { // $comment
13698 *out_anon = false;
13699 } break;
13700 case command_FieldId_runcmd: { // $comment
13701 *out_anon = false;
13702 } break;
13703 case command_FieldId_exclude: { // $comment
13704 *out_anon = false;
13705 } break;
13706 case command_FieldId_mergepath: { // $comment
13707 *out_anon = false;
13708 } break;
13709 case command_FieldId_gcov: { // $comment
13710 *out_anon = false;
13711 retval=0;
13712 out_dflt="Y";
13713 } break;
13714 case command_FieldId_ssim: { // bool: no argument required but value may be specified as gcov:Y
13715 *out_anon = false;
13716 retval=0;
13717 out_dflt="Y";
13718 } break;
13719 case command_FieldId_report: { // bool: no argument required but value may be specified as ssim:Y
13720 *out_anon = false;
13721 retval=0;
13722 out_dflt="Y";
13723 } break;
13724 case command_FieldId_capture: { // bool: no argument required but value may be specified as report:Y
13725 *out_anon = false;
13726 retval=0;
13727 out_dflt="Y";
13728 } break;
13729 case command_FieldId_xmlpretty: { // bool: no argument required but value may be specified as capture:Y
13730 *out_anon = false;
13731 retval=0;
13732 out_dflt="Y";
13733 } break;
13734 case command_FieldId_summary: { // bool: no argument required but value may be specified as xmlpretty:Y
13735 *out_anon = false;
13736 retval=0;
13737 out_dflt="Y";
13738 } break;
13739 case command_FieldId_check: { // bool: no argument required but value may be specified as summary:Y
13740 *out_anon = false;
13741 retval=0;
13742 out_dflt="Y";
13743 } break;
13744 default:
13745 retval=-1; // unrecognized
13746 }
13747 return retval;
13748}
13749
13750// --- command.atf_cov_proc.atf_cov.Start
13751// Start subprocess
13752// If subprocess already running, do nothing. Otherwise, start it
13753int command::atf_cov_Start(command::atf_cov_proc& parent) {
13754 int retval = 0;
13755 if (parent.pid == 0) {
13756 verblog(atf_cov_ToCmdline(parent)); // maybe print command
13757#ifdef WIN32
13758 algo_lib::ResolveExecFname(parent.path);
13759 tempstr cmdline(atf_cov_ToCmdline(parent));
13760 parent.pid = dospawn(Zeroterm(parent.path),Zeroterm(cmdline),parent.timeout,parent.fstdin,parent.fstdout,parent.fstderr);
13761#else
13762 parent.pid = fork();
13763 if (parent.pid == 0) { // child
13764 algo_lib::DieWithParent();
13765 if (parent.timeout > 0) {
13766 alarm(parent.timeout);
13767 }
13768 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstdin , 0);
13769 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstdout, 1);
13770 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstderr, 2);
13771 if (retval==0) retval= atf_cov_Execv(parent);
13772 if (retval != 0) { // if start fails, print error
13773 int err=errno;
13774 prerr("command.atf_cov_execv"
13775 <<Keyval("errno",err)
13776 <<Keyval("errstr",strerror(err))
13777 <<Keyval("comment","Execv failed"));
13778 }
13779 _exit(127); // if failed to start, exit anyway
13780 } else if (parent.pid == -1) {
13781 retval = errno; // failed to fork
13782 }
13783#endif
13784 }
13785 parent.status = parent.pid > 0 ? 0 : -1; // if didn't start, set error status
13786 return retval;
13787}
13788
13789// --- command.atf_cov_proc.atf_cov.StartRead
13790// Start subprocess & Read output
13791algo::Fildes command::atf_cov_StartRead(command::atf_cov_proc& parent, algo_lib::FFildes &read) {
13792 int pipefd[2];
13793 int rc=pipe(pipefd);
13794 (void)rc;
13795 read.fd.value = pipefd[0];
13796 parent.fstdout << ">&" << pipefd[1];
13797 atf_cov_Start(parent);
13798 (void)close(pipefd[1]);
13799 return read.fd;
13800}
13801
13802// --- command.atf_cov_proc.atf_cov.Kill
13803// Kill subprocess and wait
13804void command::atf_cov_Kill(command::atf_cov_proc& parent) {
13805 if (parent.pid != 0) {
13806 kill(parent.pid,9);
13807 atf_cov_Wait(parent);
13808 }
13809}
13810
13811// --- command.atf_cov_proc.atf_cov.Wait
13812// Wait for subprocess to return
13813void command::atf_cov_Wait(command::atf_cov_proc& parent) {
13814 if (parent.pid > 0) {
13815 int wait_flags = 0;
13816 int wait_status = 0;
13817 int rc = -1;
13818 do {
13819 // really wait for subprocess to exit
13820 rc = waitpid(parent.pid,&wait_status,wait_flags);
13821 } while (rc==-1 && errno==EINTR);
13822 if (rc == parent.pid) {
13823 parent.status = wait_status;
13824 parent.pid = 0;
13825 }
13826 }
13827}
13828
13829// --- command.atf_cov_proc.atf_cov.Exec
13830// Start + Wait
13831// Execute subprocess and return exit code
13832int command::atf_cov_Exec(command::atf_cov_proc& parent) {
13833 atf_cov_Start(parent);
13834 atf_cov_Wait(parent);
13835 return parent.status;
13836}
13837
13838// --- command.atf_cov_proc.atf_cov.ExecX
13839// Start + Wait, throw exception on error
13840// Execute subprocess; throw human-readable exception on error
13841void command::atf_cov_ExecX(command::atf_cov_proc& parent) {
13842 int rc = atf_cov_Exec(parent);
13843 vrfy(rc==0, tempstr() << "algo_lib.exec" << Keyval("cmd",atf_cov_ToCmdline(parent))
13844 << Keyval("comment",algo::DescribeWaitStatus(parent.status)));
13845}
13846
13847// --- command.atf_cov_proc.atf_cov.Execv
13848// Call execv()
13849// Call execv with specified parameters
13850int command::atf_cov_Execv(command::atf_cov_proc& parent) {
13851 int ret = 0;
13852 algo::StringAry args;
13853 atf_cov_ToArgv(parent, args);
13854 char **argv = (char**)alloca((ary_N(args)+1)*sizeof(*argv));
13855 ind_beg(algo::StringAry_ary_curs,arg,args) {
13856 argv[ind_curs(arg).index] = Zeroterm(arg);
13857 }ind_end;
13858 argv[ary_N(args)] = NULL;
13859 // if parent.path is relative, search for it in PATH
13860 algo_lib::ResolveExecFname(parent.path);
13861 ret = execv(Zeroterm(parent.path),argv);
13862 return ret;
13863}
13864
13865// --- command.atf_cov_proc.atf_cov.ToCmdline
13866algo::tempstr command::atf_cov_ToCmdline(command::atf_cov_proc& parent) {
13867 algo::tempstr retval;
13868 retval << parent.path << " ";
13869 command::atf_cov_PrintArgv(parent.cmd,retval);
13870 if (ch_N(parent.fstdin)) {
13871 retval << " " << parent.fstdin;
13872 }
13873 if (ch_N(parent.fstdout)) {
13874 retval << " " << parent.fstdout;
13875 }
13876 if (ch_N(parent.fstderr)) {
13877 retval << " 2" << parent.fstderr;
13878 }
13879 return retval;
13880}
13881
13882// --- command.atf_cov_proc.atf_cov.ToArgv
13883// Form array from the command line
13884void command::atf_cov_ToArgv(command::atf_cov_proc& parent, algo::StringAry& args) {
13885 ary_RemoveAll(args);
13886 ary_Alloc(args) << parent.path;
13887
13888 if (parent.cmd.in != "data") {
13889 cstring *arg = &ary_Alloc(args);
13890 *arg << "-in:";
13891 cstring_Print(parent.cmd.in, *arg);
13892 }
13893
13894 if (parent.cmd.covdir != "temp/covdata") {
13895 cstring *arg = &ary_Alloc(args);
13896 *arg << "-covdir:";
13897 cstring_Print(parent.cmd.covdir, *arg);
13898 }
13899
13900 if (parent.cmd.logfile != "") {
13901 cstring *arg = &ary_Alloc(args);
13902 *arg << "-logfile:";
13903 cstring_Print(parent.cmd.logfile, *arg);
13904 }
13905
13906 if (parent.cmd.runcmd != "") {
13907 cstring *arg = &ary_Alloc(args);
13908 *arg << "-runcmd:";
13909 cstring_Print(parent.cmd.runcmd, *arg);
13910 }
13911
13912 if (parent.cmd.exclude.expr != "(extern|include/gen|cpp/gen)/%") {
13913 cstring *arg = &ary_Alloc(args);
13914 *arg << "-exclude:";
13915 command::exclude_Print(parent.cmd, *arg);
13916 }
13917
13918 if (parent.cmd.mergepath != "") {
13919 cstring *arg = &ary_Alloc(args);
13920 *arg << "-mergepath:";
13921 cstring_Print(parent.cmd.mergepath, *arg);
13922 }
13923
13924 if (parent.cmd.gcov != false) {
13925 cstring *arg = &ary_Alloc(args);
13926 *arg << "-gcov:";
13927 bool_Print(parent.cmd.gcov, *arg);
13928 }
13929
13930 if (parent.cmd.ssim != false) {
13931 cstring *arg = &ary_Alloc(args);
13932 *arg << "-ssim:";
13933 bool_Print(parent.cmd.ssim, *arg);
13934 }
13935
13936 if (parent.cmd.report != false) {
13937 cstring *arg = &ary_Alloc(args);
13938 *arg << "-report:";
13939 bool_Print(parent.cmd.report, *arg);
13940 }
13941
13942 if (parent.cmd.capture != false) {
13943 cstring *arg = &ary_Alloc(args);
13944 *arg << "-capture:";
13945 bool_Print(parent.cmd.capture, *arg);
13946 }
13947
13948 if (parent.cmd.xmlpretty != false) {
13949 cstring *arg = &ary_Alloc(args);
13950 *arg << "-xmlpretty:";
13951 bool_Print(parent.cmd.xmlpretty, *arg);
13952 }
13953
13954 if (parent.cmd.summary != true) {
13955 cstring *arg = &ary_Alloc(args);
13956 *arg << "-summary:";
13957 bool_Print(parent.cmd.summary, *arg);
13958 }
13959
13960 if (parent.cmd.check != false) {
13961 cstring *arg = &ary_Alloc(args);
13962 *arg << "-check:";
13963 bool_Print(parent.cmd.check, *arg);
13964 }
13965 for (int i=1; i < algo_lib::_db.cmdline.verbose; ++i) {
13966 ary_Alloc(args) << "-verbose";
13967 }
13968}
13969
13970// --- command.atf_cov_proc..Uninit
13971void command::atf_cov_proc_Uninit(command::atf_cov_proc& parent) {
13972 command::atf_cov_proc &row = parent; (void)row;
13973
13974 // command.atf_cov_proc.atf_cov.Uninit (Exec) //
13975 atf_cov_Kill(parent); // kill child, ensure forward progress
13976}
13977
13978// --- command.atf_fuzz.fuzzstrat.Print
13979// Print back to string
13980void command::fuzzstrat_Print(command::atf_fuzz& parent, algo::cstring &out) {
13981 Regx_Print(parent.fuzzstrat, out);
13982}
13983
13984// --- command.atf_fuzz.fuzzstrat.ReadStrptrMaybe
13985// Read Regx from string
13986// Convert string to field. Return success value
13987bool command::fuzzstrat_ReadStrptrMaybe(command::atf_fuzz& parent, algo::strptr in) {
13988 bool retval = true;
13989 Regx_ReadSql(parent.fuzzstrat, in, true);
13990 return retval;
13991}
13992
13993// --- command.atf_fuzz..ReadFieldMaybe
13994bool command::atf_fuzz_ReadFieldMaybe(command::atf_fuzz& parent, algo::strptr field, algo::strptr strval) {
13995 bool retval = true;
13996 command::FieldId field_id;
13997 (void)value_SetStrptrMaybe(field_id,field);
13998 switch(field_id) {
13999 case command_FieldId_reprofile: {
14000 retval = algo::cstring_ReadStrptrMaybe(parent.reprofile, strval);
14001 break;
14002 }
14003 case command_FieldId_target: {
14004 retval = algo::Smallstr16_ReadStrptrMaybe(parent.target, strval);
14005 break;
14006 }
14007 case command_FieldId_args: {
14008 retval = algo::cstring_ReadStrptrMaybe(parent.args, strval);
14009 break;
14010 }
14011 case command_FieldId_inputfile: {
14012 retval = algo::cstring_ReadStrptrMaybe(parent.inputfile, strval);
14013 break;
14014 }
14015 case command_FieldId_fuzzstrat: {
14016 retval = fuzzstrat_ReadStrptrMaybe(parent, strval);
14017 break;
14018 }
14019 case command_FieldId_in: {
14020 retval = algo::cstring_ReadStrptrMaybe(parent.in, strval);
14021 break;
14022 }
14023 case command_FieldId_seed: {
14024 retval = i32_ReadStrptrMaybe(parent.seed, strval);
14025 break;
14026 }
14027 case command_FieldId_testprob: {
14028 retval = double_ReadStrptrMaybe(parent.testprob, strval);
14029 break;
14030 }
14031 default: break;
14032 }
14033 if (!retval) {
14034 algo_lib::AppendErrtext("attr",field);
14035 }
14036 return retval;
14037}
14038
14039// --- command.atf_fuzz..ReadTupleMaybe
14040// Read fields of command::atf_fuzz from attributes of ascii tuple TUPLE
14041bool command::atf_fuzz_ReadTupleMaybe(command::atf_fuzz &parent, algo::Tuple &tuple) {
14042 bool retval = true;
14043 int anon_idx = 0;
14044 ind_beg(algo::Tuple_attrs_curs,attr,tuple) {
14045 if (ch_N(attr.name) == 0) {
14046 attr.name = atf_fuzz_GetAnon(parent, anon_idx++);
14047 }
14048 retval = atf_fuzz_ReadFieldMaybe(parent, attr.name, attr.value);
14049 if (!retval) {
14050 break;
14051 }
14052 }ind_end;
14053 return retval;
14054}
14055
14056// --- command.atf_fuzz..Init
14057// Set all fields to initial values.
14058void command::atf_fuzz_Init(command::atf_fuzz& parent) {
14059 parent.reprofile = algo::strptr("temp/atf_fuzz.repro");
14060 parent.target = algo::strptr("");
14061 parent.args = algo::strptr("");
14062 parent.inputfile = algo::strptr("");
14063 Regx_ReadSql(parent.fuzzstrat, "%", true);
14064 parent.in = algo::strptr("data");
14065 parent.seed = i32(0);
14066 parent.testprob = double(1);
14067}
14068
14069// --- command.atf_fuzz..ToCmdline
14070// Convenience function that returns a full command line
14071// Assume command is in a directory called bin
14072tempstr command::atf_fuzz_ToCmdline(command::atf_fuzz& row) {
14073 tempstr ret;
14074 ret << "bin/atf_fuzz ";
14075 atf_fuzz_PrintArgv(row, ret);
14076 // inherit less intense verbose, debug options
14077 for (int i = 1; i < algo_lib::_db.cmdline.verbose; i++) {
14078 ret << " -verbose";
14079 }
14080 for (int i = 1; i < algo_lib::_db.cmdline.debug; i++) {
14081 ret << " -debug";
14082 }
14083 return ret;
14084}
14085
14086// --- command.atf_fuzz..PrintArgv
14087// print string representation of ROW to string STR
14088// cfmt:command.atf_fuzz.Argv printfmt:Tuple
14089void command::atf_fuzz_PrintArgv(command::atf_fuzz& row, algo::cstring& str) {
14090 algo::tempstr temp;
14091 (void)temp;
14092 (void)str;
14093 if (!(row.reprofile == "temp/atf_fuzz.repro")) {
14094 ch_RemoveAll(temp);
14095 cstring_Print(row.reprofile, temp);
14096 str << " -reprofile:";
14097 strptr_PrintBash(temp,str);
14098 }
14099 ch_RemoveAll(temp);
14100 Smallstr16_Print(row.target, temp);
14101 str << " -target:";
14102 strptr_PrintBash(temp,str);
14103 ch_RemoveAll(temp);
14104 cstring_Print(row.args, temp);
14105 str << " -args:";
14106 strptr_PrintBash(temp,str);
14107 if (!(row.inputfile == "")) {
14108 ch_RemoveAll(temp);
14109 cstring_Print(row.inputfile, temp);
14110 str << " -inputfile:";
14111 strptr_PrintBash(temp,str);
14112 }
14113 if (!(row.fuzzstrat.expr == "%")) {
14114 ch_RemoveAll(temp);
14115 command::fuzzstrat_Print(const_cast<command::atf_fuzz&>(row), temp);
14116 str << " -fuzzstrat:";
14117 strptr_PrintBash(temp,str);
14118 }
14119 if (!(row.in == "data")) {
14120 ch_RemoveAll(temp);
14121 cstring_Print(row.in, temp);
14122 str << " -in:";
14123 strptr_PrintBash(temp,str);
14124 }
14125 if (!(row.seed == 0)) {
14126 ch_RemoveAll(temp);
14127 i32_Print(row.seed, temp);
14128 str << " -seed:";
14129 strptr_PrintBash(temp,str);
14130 }
14131 if (!(row.testprob == 1)) {
14132 ch_RemoveAll(temp);
14133 double_Print(row.testprob, temp);
14134 str << " -testprob:";
14135 strptr_PrintBash(temp,str);
14136 }
14137}
14138
14139// --- command.atf_fuzz..GetAnon
14140algo::strptr command::atf_fuzz_GetAnon(command::atf_fuzz &parent, i32 idx) {
14141 (void)parent;//only to avoid -Wunused-parameter
14142 switch(idx) {
14143 case(0): return strptr("target", 6);
14144 case(1): return strptr("args", 4);
14145 default: return algo::strptr();
14146 }
14147}
14148
14149// --- command.atf_fuzz..NArgs
14150// Used with command lines
14151// Return # of command-line arguments that must follow this argument
14152// If FIELD is invalid, return -1
14153i32 command::atf_fuzz_NArgs(command::FieldId field, algo::strptr& out_dflt, bool* out_anon) {
14154 i32 retval = 1;
14155 switch (field) {
14156 case command_FieldId_reprofile: { // $comment
14157 *out_anon = false;
14158 } break;
14159 case command_FieldId_target: { // $comment
14160 *out_anon = true;
14161 } break;
14162 case command_FieldId_args: { // $comment
14163 *out_anon = true;
14164 } break;
14165 case command_FieldId_inputfile: { // $comment
14166 *out_anon = false;
14167 } break;
14168 case command_FieldId_fuzzstrat: { // $comment
14169 *out_anon = false;
14170 } break;
14171 case command_FieldId_in: { // $comment
14172 *out_anon = false;
14173 } break;
14174 case command_FieldId_seed: { // $comment
14175 *out_anon = false;
14176 } break;
14177 case command_FieldId_testprob: { // $comment
14178 *out_anon = false;
14179 } break;
14180 default:
14181 retval=-1; // unrecognized
14182 }
14183 (void)out_dflt;//only to avoid -Wunused-parameter
14184 return retval;
14185}
14186
14187// --- command.atf_fuzz_proc.atf_fuzz.Start
14188// Start subprocess
14189// If subprocess already running, do nothing. Otherwise, start it
14190int command::atf_fuzz_Start(command::atf_fuzz_proc& parent) {
14191 int retval = 0;
14192 if (parent.pid == 0) {
14193 verblog(atf_fuzz_ToCmdline(parent)); // maybe print command
14194#ifdef WIN32
14195 algo_lib::ResolveExecFname(parent.path);
14196 tempstr cmdline(atf_fuzz_ToCmdline(parent));
14197 parent.pid = dospawn(Zeroterm(parent.path),Zeroterm(cmdline),parent.timeout,parent.fstdin,parent.fstdout,parent.fstderr);
14198#else
14199 parent.pid = fork();
14200 if (parent.pid == 0) { // child
14201 algo_lib::DieWithParent();
14202 if (parent.timeout > 0) {
14203 alarm(parent.timeout);
14204 }
14205 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstdin , 0);
14206 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstdout, 1);
14207 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstderr, 2);
14208 if (retval==0) retval= atf_fuzz_Execv(parent);
14209 if (retval != 0) { // if start fails, print error
14210 int err=errno;
14211 prerr("command.atf_fuzz_execv"
14212 <<Keyval("errno",err)
14213 <<Keyval("errstr",strerror(err))
14214 <<Keyval("comment","Execv failed"));
14215 }
14216 _exit(127); // if failed to start, exit anyway
14217 } else if (parent.pid == -1) {
14218 retval = errno; // failed to fork
14219 }
14220#endif
14221 }
14222 parent.status = parent.pid > 0 ? 0 : -1; // if didn't start, set error status
14223 return retval;
14224}
14225
14226// --- command.atf_fuzz_proc.atf_fuzz.StartRead
14227// Start subprocess & Read output
14228algo::Fildes command::atf_fuzz_StartRead(command::atf_fuzz_proc& parent, algo_lib::FFildes &read) {
14229 int pipefd[2];
14230 int rc=pipe(pipefd);
14231 (void)rc;
14232 read.fd.value = pipefd[0];
14233 parent.fstdout << ">&" << pipefd[1];
14234 atf_fuzz_Start(parent);
14235 (void)close(pipefd[1]);
14236 return read.fd;
14237}
14238
14239// --- command.atf_fuzz_proc.atf_fuzz.Kill
14240// Kill subprocess and wait
14241void command::atf_fuzz_Kill(command::atf_fuzz_proc& parent) {
14242 if (parent.pid != 0) {
14243 kill(parent.pid,9);
14244 atf_fuzz_Wait(parent);
14245 }
14246}
14247
14248// --- command.atf_fuzz_proc.atf_fuzz.Wait
14249// Wait for subprocess to return
14250void command::atf_fuzz_Wait(command::atf_fuzz_proc& parent) {
14251 if (parent.pid > 0) {
14252 int wait_flags = 0;
14253 int wait_status = 0;
14254 int rc = -1;
14255 do {
14256 // really wait for subprocess to exit
14257 rc = waitpid(parent.pid,&wait_status,wait_flags);
14258 } while (rc==-1 && errno==EINTR);
14259 if (rc == parent.pid) {
14260 parent.status = wait_status;
14261 parent.pid = 0;
14262 }
14263 }
14264}
14265
14266// --- command.atf_fuzz_proc.atf_fuzz.Exec
14267// Start + Wait
14268// Execute subprocess and return exit code
14269int command::atf_fuzz_Exec(command::atf_fuzz_proc& parent) {
14270 atf_fuzz_Start(parent);
14271 atf_fuzz_Wait(parent);
14272 return parent.status;
14273}
14274
14275// --- command.atf_fuzz_proc.atf_fuzz.ExecX
14276// Start + Wait, throw exception on error
14277// Execute subprocess; throw human-readable exception on error
14278void command::atf_fuzz_ExecX(command::atf_fuzz_proc& parent) {
14279 int rc = atf_fuzz_Exec(parent);
14280 vrfy(rc==0, tempstr() << "algo_lib.exec" << Keyval("cmd",atf_fuzz_ToCmdline(parent))
14281 << Keyval("comment",algo::DescribeWaitStatus(parent.status)));
14282}
14283
14284// --- command.atf_fuzz_proc.atf_fuzz.Execv
14285// Call execv()
14286// Call execv with specified parameters
14287int command::atf_fuzz_Execv(command::atf_fuzz_proc& parent) {
14288 int ret = 0;
14289 algo::StringAry args;
14290 atf_fuzz_ToArgv(parent, args);
14291 char **argv = (char**)alloca((ary_N(args)+1)*sizeof(*argv));
14292 ind_beg(algo::StringAry_ary_curs,arg,args) {
14293 argv[ind_curs(arg).index] = Zeroterm(arg);
14294 }ind_end;
14295 argv[ary_N(args)] = NULL;
14296 // if parent.path is relative, search for it in PATH
14297 algo_lib::ResolveExecFname(parent.path);
14298 ret = execv(Zeroterm(parent.path),argv);
14299 return ret;
14300}
14301
14302// --- command.atf_fuzz_proc.atf_fuzz.ToCmdline
14303algo::tempstr command::atf_fuzz_ToCmdline(command::atf_fuzz_proc& parent) {
14304 algo::tempstr retval;
14305 retval << parent.path << " ";
14306 command::atf_fuzz_PrintArgv(parent.cmd,retval);
14307 if (ch_N(parent.fstdin)) {
14308 retval << " " << parent.fstdin;
14309 }
14310 if (ch_N(parent.fstdout)) {
14311 retval << " " << parent.fstdout;
14312 }
14313 if (ch_N(parent.fstderr)) {
14314 retval << " 2" << parent.fstderr;
14315 }
14316 return retval;
14317}
14318
14319// --- command.atf_fuzz_proc.atf_fuzz.ToArgv
14320// Form array from the command line
14321void command::atf_fuzz_ToArgv(command::atf_fuzz_proc& parent, algo::StringAry& args) {
14322 ary_RemoveAll(args);
14323 ary_Alloc(args) << parent.path;
14324
14325 if (parent.cmd.reprofile != "temp/atf_fuzz.repro") {
14326 cstring *arg = &ary_Alloc(args);
14327 *arg << "-reprofile:";
14328 cstring_Print(parent.cmd.reprofile, *arg);
14329 }
14330
14331 if (parent.cmd.target != "") {
14332 cstring *arg = &ary_Alloc(args);
14333 *arg << "-target:";
14334 Smallstr16_Print(parent.cmd.target, *arg);
14335 }
14336
14337 if (parent.cmd.args != "") {
14338 cstring *arg = &ary_Alloc(args);
14339 *arg << "-args:";
14340 cstring_Print(parent.cmd.args, *arg);
14341 }
14342
14343 if (parent.cmd.inputfile != "") {
14344 cstring *arg = &ary_Alloc(args);
14345 *arg << "-inputfile:";
14346 cstring_Print(parent.cmd.inputfile, *arg);
14347 }
14348
14349 if (parent.cmd.fuzzstrat.expr != "%") {
14350 cstring *arg = &ary_Alloc(args);
14351 *arg << "-fuzzstrat:";
14352 command::fuzzstrat_Print(parent.cmd, *arg);
14353 }
14354
14355 if (parent.cmd.in != "data") {
14356 cstring *arg = &ary_Alloc(args);
14357 *arg << "-in:";
14358 cstring_Print(parent.cmd.in, *arg);
14359 }
14360
14361 if (parent.cmd.seed != 0) {
14362 cstring *arg = &ary_Alloc(args);
14363 *arg << "-seed:";
14364 i32_Print(parent.cmd.seed, *arg);
14365 }
14366
14367 if (parent.cmd.testprob != 1) {
14368 cstring *arg = &ary_Alloc(args);
14369 *arg << "-testprob:";
14370 double_Print(parent.cmd.testprob, *arg);
14371 }
14372 for (int i=1; i < algo_lib::_db.cmdline.verbose; ++i) {
14373 ary_Alloc(args) << "-verbose";
14374 }
14375}
14376
14377// --- command.atf_fuzz_proc..Uninit
14378void command::atf_fuzz_proc_Uninit(command::atf_fuzz_proc& parent) {
14379 command::atf_fuzz_proc &row = parent; (void)row;
14380
14381 // command.atf_fuzz_proc.atf_fuzz.Uninit (Exec) //
14382 atf_fuzz_Kill(parent); // kill child, ensure forward progress
14383}
14384
14385// --- command.atf_gcli.gtblacttst.Print
14386// Print back to string
14387void command::gtblacttst_Print(command::atf_gcli& parent, algo::cstring &out) {
14388 Regx_Print(parent.gtblacttst, out);
14389}
14390
14391// --- command.atf_gcli.gtblacttst.ReadStrptrMaybe
14392// Read Regx from string
14393// Convert string to field. Return success value
14394bool command::gtblacttst_ReadStrptrMaybe(command::atf_gcli& parent, algo::strptr in) {
14395 bool retval = true;
14396 Regx_ReadSql(parent.gtblacttst, in, true);
14397 return retval;
14398}
14399
14400// --- command.atf_gcli..ReadFieldMaybe
14401bool command::atf_gcli_ReadFieldMaybe(command::atf_gcli& parent, algo::strptr field, algo::strptr strval) {
14402 bool retval = true;
14403 command::FieldId field_id;
14404 (void)value_SetStrptrMaybe(field_id,field);
14405 switch(field_id) {
14406 case command_FieldId_in: {
14407 retval = algo::cstring_ReadStrptrMaybe(parent.in, strval);
14408 break;
14409 }
14410 case command_FieldId_gtblacttst: {
14411 retval = gtblacttst_ReadStrptrMaybe(parent, strval);
14412 break;
14413 }
14414 case command_FieldId_id: {
14415 retval = algo::cstring_ReadStrptrMaybe(parent.id, strval);
14416 break;
14417 }
14418 case command_FieldId_mr: {
14419 retval = algo::cstring_ReadStrptrMaybe(parent.mr, strval);
14420 break;
14421 }
14422 case command_FieldId_note: {
14423 retval = algo::cstring_ReadStrptrMaybe(parent.note, strval);
14424 break;
14425 }
14426 case command_FieldId_capture: {
14427 retval = bool_ReadStrptrMaybe(parent.capture, strval);
14428 break;
14429 }
14430 case command_FieldId_skip_init: {
14431 retval = bool_ReadStrptrMaybe(parent.skip_init, strval);
14432 break;
14433 }
14434 case command_FieldId_skip_git_init: {
14435 retval = bool_ReadStrptrMaybe(parent.skip_git_init, strval);
14436 break;
14437 }
14438 case command_FieldId_dry_run: {
14439 retval = bool_ReadStrptrMaybe(parent.dry_run, strval);
14440 break;
14441 }
14442 default: break;
14443 }
14444 if (!retval) {
14445 algo_lib::AppendErrtext("attr",field);
14446 }
14447 return retval;
14448}
14449
14450// --- command.atf_gcli..ReadTupleMaybe
14451// Read fields of command::atf_gcli from attributes of ascii tuple TUPLE
14452bool command::atf_gcli_ReadTupleMaybe(command::atf_gcli &parent, algo::Tuple &tuple) {
14453 bool retval = true;
14454 ind_beg(algo::Tuple_attrs_curs,attr,tuple) {
14455 retval = atf_gcli_ReadFieldMaybe(parent, attr.name, attr.value);
14456 if (!retval) {
14457 break;
14458 }
14459 }ind_end;
14460 return retval;
14461}
14462
14463// --- command.atf_gcli..Init
14464// Set all fields to initial values.
14465void command::atf_gcli_Init(command::atf_gcli& parent) {
14466 parent.in = algo::strptr("data");
14467 Regx_ReadSql(parent.gtblacttst, "%", true);
14468 parent.id = algo::strptr("");
14469 parent.mr = algo::strptr("");
14470 parent.note = algo::strptr("");
14471 parent.capture = bool(false);
14472 parent.skip_init = bool(false);
14473 parent.skip_git_init = bool(false);
14474 parent.dry_run = bool(false);
14475}
14476
14477// --- command.atf_gcli..ToCmdline
14478// Convenience function that returns a full command line
14479// Assume command is in a directory called bin
14480tempstr command::atf_gcli_ToCmdline(command::atf_gcli& row) {
14481 tempstr ret;
14482 ret << "bin/atf_gcli ";
14483 atf_gcli_PrintArgv(row, ret);
14484 // inherit less intense verbose, debug options
14485 for (int i = 1; i < algo_lib::_db.cmdline.verbose; i++) {
14486 ret << " -verbose";
14487 }
14488 for (int i = 1; i < algo_lib::_db.cmdline.debug; i++) {
14489 ret << " -debug";
14490 }
14491 return ret;
14492}
14493
14494// --- command.atf_gcli..PrintArgv
14495// print string representation of ROW to string STR
14496// cfmt:command.atf_gcli.Argv printfmt:Tuple
14497void command::atf_gcli_PrintArgv(command::atf_gcli& row, algo::cstring& str) {
14498 algo::tempstr temp;
14499 (void)temp;
14500 (void)str;
14501 if (!(row.in == "data")) {
14502 ch_RemoveAll(temp);
14503 cstring_Print(row.in, temp);
14504 str << " -in:";
14505 strptr_PrintBash(temp,str);
14506 }
14507 if (!(row.gtblacttst.expr == "%")) {
14508 ch_RemoveAll(temp);
14509 command::gtblacttst_Print(const_cast<command::atf_gcli&>(row), temp);
14510 str << " -gtblacttst:";
14511 strptr_PrintBash(temp,str);
14512 }
14513 if (!(row.id == "")) {
14514 ch_RemoveAll(temp);
14515 cstring_Print(row.id, temp);
14516 str << " -id:";
14517 strptr_PrintBash(temp,str);
14518 }
14519 if (!(row.mr == "")) {
14520 ch_RemoveAll(temp);
14521 cstring_Print(row.mr, temp);
14522 str << " -mr:";
14523 strptr_PrintBash(temp,str);
14524 }
14525 if (!(row.note == "")) {
14526 ch_RemoveAll(temp);
14527 cstring_Print(row.note, temp);
14528 str << " -note:";
14529 strptr_PrintBash(temp,str);
14530 }
14531 if (!(row.capture == false)) {
14532 ch_RemoveAll(temp);
14533 bool_Print(row.capture, temp);
14534 str << " -capture:";
14535 strptr_PrintBash(temp,str);
14536 }
14537 if (!(row.skip_init == false)) {
14538 ch_RemoveAll(temp);
14539 bool_Print(row.skip_init, temp);
14540 str << " -skip_init:";
14541 strptr_PrintBash(temp,str);
14542 }
14543 if (!(row.skip_git_init == false)) {
14544 ch_RemoveAll(temp);
14545 bool_Print(row.skip_git_init, temp);
14546 str << " -skip_git_init:";
14547 strptr_PrintBash(temp,str);
14548 }
14549 if (!(row.dry_run == false)) {
14550 ch_RemoveAll(temp);
14551 bool_Print(row.dry_run, temp);
14552 str << " -dry_run:";
14553 strptr_PrintBash(temp,str);
14554 }
14555}
14556
14557// --- command.atf_gcli..NArgs
14558// Used with command lines
14559// Return # of command-line arguments that must follow this argument
14560// If FIELD is invalid, return -1
14561i32 command::atf_gcli_NArgs(command::FieldId field, algo::strptr& out_dflt, bool* out_anon) {
14562 i32 retval = 1;
14563 switch (field) {
14564 case command_FieldId_in: { // $comment
14565 *out_anon = false;
14566 } break;
14567 case command_FieldId_gtblacttst: { // $comment
14568 *out_anon = false;
14569 } break;
14570 case command_FieldId_id: { // $comment
14571 *out_anon = false;
14572 } break;
14573 case command_FieldId_mr: { // $comment
14574 *out_anon = false;
14575 } break;
14576 case command_FieldId_note: { // $comment
14577 *out_anon = false;
14578 } break;
14579 case command_FieldId_capture: { // $comment
14580 *out_anon = false;
14581 retval=0;
14582 out_dflt="Y";
14583 } break;
14584 case command_FieldId_skip_init: { // bool: no argument required but value may be specified as capture:Y
14585 *out_anon = false;
14586 retval=0;
14587 out_dflt="Y";
14588 } break;
14589 case command_FieldId_skip_git_init: { // bool: no argument required but value may be specified as skip_init:Y
14590 *out_anon = false;
14591 retval=0;
14592 out_dflt="Y";
14593 } break;
14594 case command_FieldId_dry_run: { // bool: no argument required but value may be specified as skip_git_init:Y
14595 *out_anon = false;
14596 retval=0;
14597 out_dflt="Y";
14598 } break;
14599 default:
14600 retval=-1; // unrecognized
14601 }
14602 return retval;
14603}
14604
14605// --- command.atf_gcli_proc.atf_gcli.Start
14606// Start subprocess
14607// If subprocess already running, do nothing. Otherwise, start it
14608int command::atf_gcli_Start(command::atf_gcli_proc& parent) {
14609 int retval = 0;
14610 if (parent.pid == 0) {
14611 verblog(atf_gcli_ToCmdline(parent)); // maybe print command
14612#ifdef WIN32
14613 algo_lib::ResolveExecFname(parent.path);
14614 tempstr cmdline(atf_gcli_ToCmdline(parent));
14615 parent.pid = dospawn(Zeroterm(parent.path),Zeroterm(cmdline),parent.timeout,parent.fstdin,parent.fstdout,parent.fstderr);
14616#else
14617 parent.pid = fork();
14618 if (parent.pid == 0) { // child
14619 algo_lib::DieWithParent();
14620 if (parent.timeout > 0) {
14621 alarm(parent.timeout);
14622 }
14623 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstdin , 0);
14624 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstdout, 1);
14625 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstderr, 2);
14626 if (retval==0) retval= atf_gcli_Execv(parent);
14627 if (retval != 0) { // if start fails, print error
14628 int err=errno;
14629 prerr("command.atf_gcli_execv"
14630 <<Keyval("errno",err)
14631 <<Keyval("errstr",strerror(err))
14632 <<Keyval("comment","Execv failed"));
14633 }
14634 _exit(127); // if failed to start, exit anyway
14635 } else if (parent.pid == -1) {
14636 retval = errno; // failed to fork
14637 }
14638#endif
14639 }
14640 parent.status = parent.pid > 0 ? 0 : -1; // if didn't start, set error status
14641 return retval;
14642}
14643
14644// --- command.atf_gcli_proc.atf_gcli.StartRead
14645// Start subprocess & Read output
14646algo::Fildes command::atf_gcli_StartRead(command::atf_gcli_proc& parent, algo_lib::FFildes &read) {
14647 int pipefd[2];
14648 int rc=pipe(pipefd);
14649 (void)rc;
14650 read.fd.value = pipefd[0];
14651 parent.fstdout << ">&" << pipefd[1];
14652 atf_gcli_Start(parent);
14653 (void)close(pipefd[1]);
14654 return read.fd;
14655}
14656
14657// --- command.atf_gcli_proc.atf_gcli.Kill
14658// Kill subprocess and wait
14659void command::atf_gcli_Kill(command::atf_gcli_proc& parent) {
14660 if (parent.pid != 0) {
14661 kill(parent.pid,9);
14662 atf_gcli_Wait(parent);
14663 }
14664}
14665
14666// --- command.atf_gcli_proc.atf_gcli.Wait
14667// Wait for subprocess to return
14668void command::atf_gcli_Wait(command::atf_gcli_proc& parent) {
14669 if (parent.pid > 0) {
14670 int wait_flags = 0;
14671 int wait_status = 0;
14672 int rc = -1;
14673 do {
14674 // really wait for subprocess to exit
14675 rc = waitpid(parent.pid,&wait_status,wait_flags);
14676 } while (rc==-1 && errno==EINTR);
14677 if (rc == parent.pid) {
14678 parent.status = wait_status;
14679 parent.pid = 0;
14680 }
14681 }
14682}
14683
14684// --- command.atf_gcli_proc.atf_gcli.Exec
14685// Start + Wait
14686// Execute subprocess and return exit code
14687int command::atf_gcli_Exec(command::atf_gcli_proc& parent) {
14688 atf_gcli_Start(parent);
14689 atf_gcli_Wait(parent);
14690 return parent.status;
14691}
14692
14693// --- command.atf_gcli_proc.atf_gcli.ExecX
14694// Start + Wait, throw exception on error
14695// Execute subprocess; throw human-readable exception on error
14696void command::atf_gcli_ExecX(command::atf_gcli_proc& parent) {
14697 int rc = atf_gcli_Exec(parent);
14698 vrfy(rc==0, tempstr() << "algo_lib.exec" << Keyval("cmd",atf_gcli_ToCmdline(parent))
14699 << Keyval("comment",algo::DescribeWaitStatus(parent.status)));
14700}
14701
14702// --- command.atf_gcli_proc.atf_gcli.Execv
14703// Call execv()
14704// Call execv with specified parameters
14705int command::atf_gcli_Execv(command::atf_gcli_proc& parent) {
14706 int ret = 0;
14707 algo::StringAry args;
14708 atf_gcli_ToArgv(parent, args);
14709 char **argv = (char**)alloca((ary_N(args)+1)*sizeof(*argv));
14710 ind_beg(algo::StringAry_ary_curs,arg,args) {
14711 argv[ind_curs(arg).index] = Zeroterm(arg);
14712 }ind_end;
14713 argv[ary_N(args)] = NULL;
14714 // if parent.path is relative, search for it in PATH
14715 algo_lib::ResolveExecFname(parent.path);
14716 ret = execv(Zeroterm(parent.path),argv);
14717 return ret;
14718}
14719
14720// --- command.atf_gcli_proc.atf_gcli.ToCmdline
14721algo::tempstr command::atf_gcli_ToCmdline(command::atf_gcli_proc& parent) {
14722 algo::tempstr retval;
14723 retval << parent.path << " ";
14724 command::atf_gcli_PrintArgv(parent.cmd,retval);
14725 if (ch_N(parent.fstdin)) {
14726 retval << " " << parent.fstdin;
14727 }
14728 if (ch_N(parent.fstdout)) {
14729 retval << " " << parent.fstdout;
14730 }
14731 if (ch_N(parent.fstderr)) {
14732 retval << " 2" << parent.fstderr;
14733 }
14734 return retval;
14735}
14736
14737// --- command.atf_gcli_proc.atf_gcli.ToArgv
14738// Form array from the command line
14739void command::atf_gcli_ToArgv(command::atf_gcli_proc& parent, algo::StringAry& args) {
14740 ary_RemoveAll(args);
14741 ary_Alloc(args) << parent.path;
14742
14743 if (parent.cmd.in != "data") {
14744 cstring *arg = &ary_Alloc(args);
14745 *arg << "-in:";
14746 cstring_Print(parent.cmd.in, *arg);
14747 }
14748
14749 if (parent.cmd.gtblacttst.expr != "%") {
14750 cstring *arg = &ary_Alloc(args);
14751 *arg << "-gtblacttst:";
14752 command::gtblacttst_Print(parent.cmd, *arg);
14753 }
14754
14755 if (parent.cmd.id != "") {
14756 cstring *arg = &ary_Alloc(args);
14757 *arg << "-id:";
14758 cstring_Print(parent.cmd.id, *arg);
14759 }
14760
14761 if (parent.cmd.mr != "") {
14762 cstring *arg = &ary_Alloc(args);
14763 *arg << "-mr:";
14764 cstring_Print(parent.cmd.mr, *arg);
14765 }
14766
14767 if (parent.cmd.note != "") {
14768 cstring *arg = &ary_Alloc(args);
14769 *arg << "-note:";
14770 cstring_Print(parent.cmd.note, *arg);
14771 }
14772
14773 if (parent.cmd.capture != false) {
14774 cstring *arg = &ary_Alloc(args);
14775 *arg << "-capture:";
14776 bool_Print(parent.cmd.capture, *arg);
14777 }
14778
14779 if (parent.cmd.skip_init != false) {
14780 cstring *arg = &ary_Alloc(args);
14781 *arg << "-skip_init:";
14782 bool_Print(parent.cmd.skip_init, *arg);
14783 }
14784
14785 if (parent.cmd.skip_git_init != false) {
14786 cstring *arg = &ary_Alloc(args);
14787 *arg << "-skip_git_init:";
14788 bool_Print(parent.cmd.skip_git_init, *arg);
14789 }
14790
14791 if (parent.cmd.dry_run != false) {
14792 cstring *arg = &ary_Alloc(args);
14793 *arg << "-dry_run:";
14794 bool_Print(parent.cmd.dry_run, *arg);
14795 }
14796 for (int i=1; i < algo_lib::_db.cmdline.verbose; ++i) {
14797 ary_Alloc(args) << "-verbose";
14798 }
14799}
14800
14801// --- command.atf_gcli_proc..Uninit
14802void command::atf_gcli_proc_Uninit(command::atf_gcli_proc& parent) {
14803 command::atf_gcli_proc &row = parent; (void)row;
14804
14805 // command.atf_gcli_proc.atf_gcli.Uninit (Exec) //
14806 atf_gcli_Kill(parent); // kill child, ensure forward progress
14807}
14808
14809// --- command.atf_netio..ReadFieldMaybe
14810bool command::atf_netio_ReadFieldMaybe(command::atf_netio& parent, algo::strptr field, algo::strptr strval) {
14811 bool retval = true;
14812 command::FieldId field_id;
14813 (void)value_SetStrptrMaybe(field_id,field);
14814 switch(field_id) {
14815 case command_FieldId_in: {
14816 retval = algo::cstring_ReadStrptrMaybe(parent.in, strval);
14817 break;
14818 }
14819 case command_FieldId_randomize_ports: {
14820 retval = bool_ReadStrptrMaybe(parent.randomize_ports, strval);
14821 break;
14822 }
14823 default: break;
14824 }
14825 if (!retval) {
14826 algo_lib::AppendErrtext("attr",field);
14827 }
14828 return retval;
14829}
14830
14831// --- command.atf_netio..ReadTupleMaybe
14832// Read fields of command::atf_netio from attributes of ascii tuple TUPLE
14833bool command::atf_netio_ReadTupleMaybe(command::atf_netio &parent, algo::Tuple &tuple) {
14834 bool retval = true;
14835 ind_beg(algo::Tuple_attrs_curs,attr,tuple) {
14836 retval = atf_netio_ReadFieldMaybe(parent, attr.name, attr.value);
14837 if (!retval) {
14838 break;
14839 }
14840 }ind_end;
14841 return retval;
14842}
14843
14844// --- command.atf_netio..ToCmdline
14845// Convenience function that returns a full command line
14846// Assume command is in a directory called bin
14847tempstr command::atf_netio_ToCmdline(command::atf_netio& row) {
14848 tempstr ret;
14849 ret << "bin/atf_netio ";
14850 atf_netio_PrintArgv(row, ret);
14851 // inherit less intense verbose, debug options
14852 for (int i = 1; i < algo_lib::_db.cmdline.verbose; i++) {
14853 ret << " -verbose";
14854 }
14855 for (int i = 1; i < algo_lib::_db.cmdline.debug; i++) {
14856 ret << " -debug";
14857 }
14858 return ret;
14859}
14860
14861// --- command.atf_netio..PrintArgv
14862// print string representation of ROW to string STR
14863// cfmt:command.atf_netio.Argv printfmt:Tuple
14864void command::atf_netio_PrintArgv(command::atf_netio& row, algo::cstring& str) {
14865 algo::tempstr temp;
14866 (void)temp;
14867 (void)str;
14868 if (!(row.in == "data")) {
14869 ch_RemoveAll(temp);
14870 cstring_Print(row.in, temp);
14871 str << " -in:";
14872 strptr_PrintBash(temp,str);
14873 }
14874 if (!(row.randomize_ports == true)) {
14875 ch_RemoveAll(temp);
14876 bool_Print(row.randomize_ports, temp);
14877 str << " -randomize_ports:";
14878 strptr_PrintBash(temp,str);
14879 }
14880}
14881
14882// --- command.atf_netio..NArgs
14883// Used with command lines
14884// Return # of command-line arguments that must follow this argument
14885// If FIELD is invalid, return -1
14886i32 command::atf_netio_NArgs(command::FieldId field, algo::strptr& out_dflt, bool* out_anon) {
14887 i32 retval = 1;
14888 switch (field) {
14889 case command_FieldId_in: { // $comment
14890 *out_anon = false;
14891 } break;
14892 case command_FieldId_randomize_ports: { // $comment
14893 *out_anon = false;
14894 retval=0;
14895 out_dflt="Y";
14896 } break;
14897 default:
14898 retval=-1; // unrecognized
14899 }
14900 return retval;
14901}
14902
14903// --- command.atf_netio_proc.atf_netio.Start
14904// Start subprocess
14905// If subprocess already running, do nothing. Otherwise, start it
14906int command::atf_netio_Start(command::atf_netio_proc& parent) {
14907 int retval = 0;
14908 if (parent.pid == 0) {
14909 verblog(atf_netio_ToCmdline(parent)); // maybe print command
14910#ifdef WIN32
14911 algo_lib::ResolveExecFname(parent.path);
14912 tempstr cmdline(atf_netio_ToCmdline(parent));
14913 parent.pid = dospawn(Zeroterm(parent.path),Zeroterm(cmdline),parent.timeout,parent.fstdin,parent.fstdout,parent.fstderr);
14914#else
14915 parent.pid = fork();
14916 if (parent.pid == 0) { // child
14917 algo_lib::DieWithParent();
14918 if (parent.timeout > 0) {
14919 alarm(parent.timeout);
14920 }
14921 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstdin , 0);
14922 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstdout, 1);
14923 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstderr, 2);
14924 if (retval==0) retval= atf_netio_Execv(parent);
14925 if (retval != 0) { // if start fails, print error
14926 int err=errno;
14927 prerr("command.atf_netio_execv"
14928 <<Keyval("errno",err)
14929 <<Keyval("errstr",strerror(err))
14930 <<Keyval("comment","Execv failed"));
14931 }
14932 _exit(127); // if failed to start, exit anyway
14933 } else if (parent.pid == -1) {
14934 retval = errno; // failed to fork
14935 }
14936#endif
14937 }
14938 parent.status = parent.pid > 0 ? 0 : -1; // if didn't start, set error status
14939 return retval;
14940}
14941
14942// --- command.atf_netio_proc.atf_netio.StartRead
14943// Start subprocess & Read output
14944algo::Fildes command::atf_netio_StartRead(command::atf_netio_proc& parent, algo_lib::FFildes &read) {
14945 int pipefd[2];
14946 int rc=pipe(pipefd);
14947 (void)rc;
14948 read.fd.value = pipefd[0];
14949 parent.fstdout << ">&" << pipefd[1];
14950 atf_netio_Start(parent);
14951 (void)close(pipefd[1]);
14952 return read.fd;
14953}
14954
14955// --- command.atf_netio_proc.atf_netio.Kill
14956// Kill subprocess and wait
14957void command::atf_netio_Kill(command::atf_netio_proc& parent) {
14958 if (parent.pid != 0) {
14959 kill(parent.pid,9);
14960 atf_netio_Wait(parent);
14961 }
14962}
14963
14964// --- command.atf_netio_proc.atf_netio.Wait
14965// Wait for subprocess to return
14966void command::atf_netio_Wait(command::atf_netio_proc& parent) {
14967 if (parent.pid > 0) {
14968 int wait_flags = 0;
14969 int wait_status = 0;
14970 int rc = -1;
14971 do {
14972 // really wait for subprocess to exit
14973 rc = waitpid(parent.pid,&wait_status,wait_flags);
14974 } while (rc==-1 && errno==EINTR);
14975 if (rc == parent.pid) {
14976 parent.status = wait_status;
14977 parent.pid = 0;
14978 }
14979 }
14980}
14981
14982// --- command.atf_netio_proc.atf_netio.Exec
14983// Start + Wait
14984// Execute subprocess and return exit code
14985int command::atf_netio_Exec(command::atf_netio_proc& parent) {
14986 atf_netio_Start(parent);
14987 atf_netio_Wait(parent);
14988 return parent.status;
14989}
14990
14991// --- command.atf_netio_proc.atf_netio.ExecX
14992// Start + Wait, throw exception on error
14993// Execute subprocess; throw human-readable exception on error
14994void command::atf_netio_ExecX(command::atf_netio_proc& parent) {
14995 int rc = atf_netio_Exec(parent);
14996 vrfy(rc==0, tempstr() << "algo_lib.exec" << Keyval("cmd",atf_netio_ToCmdline(parent))
14997 << Keyval("comment",algo::DescribeWaitStatus(parent.status)));
14998}
14999
15000// --- command.atf_netio_proc.atf_netio.Execv
15001// Call execv()
15002// Call execv with specified parameters
15003int command::atf_netio_Execv(command::atf_netio_proc& parent) {
15004 int ret = 0;
15005 algo::StringAry args;
15006 atf_netio_ToArgv(parent, args);
15007 char **argv = (char**)alloca((ary_N(args)+1)*sizeof(*argv));
15008 ind_beg(algo::StringAry_ary_curs,arg,args) {
15009 argv[ind_curs(arg).index] = Zeroterm(arg);
15010 }ind_end;
15011 argv[ary_N(args)] = NULL;
15012 // if parent.path is relative, search for it in PATH
15013 algo_lib::ResolveExecFname(parent.path);
15014 ret = execv(Zeroterm(parent.path),argv);
15015 return ret;
15016}
15017
15018// --- command.atf_netio_proc.atf_netio.ToCmdline
15019algo::tempstr command::atf_netio_ToCmdline(command::atf_netio_proc& parent) {
15020 algo::tempstr retval;
15021 retval << parent.path << " ";
15022 command::atf_netio_PrintArgv(parent.cmd,retval);
15023 if (ch_N(parent.fstdin)) {
15024 retval << " " << parent.fstdin;
15025 }
15026 if (ch_N(parent.fstdout)) {
15027 retval << " " << parent.fstdout;
15028 }
15029 if (ch_N(parent.fstderr)) {
15030 retval << " 2" << parent.fstderr;
15031 }
15032 return retval;
15033}
15034
15035// --- command.atf_netio_proc.atf_netio.ToArgv
15036// Form array from the command line
15037void command::atf_netio_ToArgv(command::atf_netio_proc& parent, algo::StringAry& args) {
15038 ary_RemoveAll(args);
15039 ary_Alloc(args) << parent.path;
15040
15041 if (parent.cmd.in != "data") {
15042 cstring *arg = &ary_Alloc(args);
15043 *arg << "-in:";
15044 cstring_Print(parent.cmd.in, *arg);
15045 }
15046
15047 if (parent.cmd.randomize_ports != true) {
15048 cstring *arg = &ary_Alloc(args);
15049 *arg << "-randomize_ports:";
15050 bool_Print(parent.cmd.randomize_ports, *arg);
15051 }
15052 for (int i=1; i < algo_lib::_db.cmdline.verbose; ++i) {
15053 ary_Alloc(args) << "-verbose";
15054 }
15055}
15056
15057// --- command.atf_netio_proc..Uninit
15058void command::atf_netio_proc_Uninit(command::atf_netio_proc& parent) {
15059 command::atf_netio_proc &row = parent; (void)row;
15060
15061 // command.atf_netio_proc.atf_netio.Uninit (Exec) //
15062 atf_netio_Kill(parent); // kill child, ensure forward progress
15063}
15064
15065// --- command.atf_nrun..ReadFieldMaybe
15066bool command::atf_nrun_ReadFieldMaybe(command::atf_nrun& parent, algo::strptr field, algo::strptr strval) {
15067 bool retval = true;
15068 command::FieldId field_id;
15069 (void)value_SetStrptrMaybe(field_id,field);
15070 switch(field_id) {
15071 case command_FieldId_in: {
15072 retval = algo::cstring_ReadStrptrMaybe(parent.in, strval);
15073 break;
15074 }
15075 case command_FieldId_maxjobs: {
15076 retval = i32_ReadStrptrMaybe(parent.maxjobs, strval);
15077 break;
15078 }
15079 case command_FieldId_ncmd: {
15080 retval = i32_ReadStrptrMaybe(parent.ncmd, strval);
15081 break;
15082 }
15083 default: break;
15084 }
15085 if (!retval) {
15086 algo_lib::AppendErrtext("attr",field);
15087 }
15088 return retval;
15089}
15090
15091// --- command.atf_nrun..ReadTupleMaybe
15092// Read fields of command::atf_nrun from attributes of ascii tuple TUPLE
15093bool command::atf_nrun_ReadTupleMaybe(command::atf_nrun &parent, algo::Tuple &tuple) {
15094 bool retval = true;
15095 int anon_idx = 0;
15096 ind_beg(algo::Tuple_attrs_curs,attr,tuple) {
15097 if (ch_N(attr.name) == 0) {
15098 attr.name = atf_nrun_GetAnon(parent, anon_idx++);
15099 }
15100 retval = atf_nrun_ReadFieldMaybe(parent, attr.name, attr.value);
15101 if (!retval) {
15102 break;
15103 }
15104 }ind_end;
15105 return retval;
15106}
15107
15108// --- command.atf_nrun..ToCmdline
15109// Convenience function that returns a full command line
15110// Assume command is in a directory called bin
15111tempstr command::atf_nrun_ToCmdline(command::atf_nrun& row) {
15112 tempstr ret;
15113 ret << "bin/atf_nrun ";
15114 atf_nrun_PrintArgv(row, ret);
15115 // inherit less intense verbose, debug options
15116 for (int i = 1; i < algo_lib::_db.cmdline.verbose; i++) {
15117 ret << " -verbose";
15118 }
15119 for (int i = 1; i < algo_lib::_db.cmdline.debug; i++) {
15120 ret << " -debug";
15121 }
15122 return ret;
15123}
15124
15125// --- command.atf_nrun..PrintArgv
15126// print string representation of ROW to string STR
15127// cfmt:command.atf_nrun.Argv printfmt:Tuple
15128void command::atf_nrun_PrintArgv(command::atf_nrun& row, algo::cstring& str) {
15129 algo::tempstr temp;
15130 (void)temp;
15131 (void)str;
15132 if (!(row.in == "data")) {
15133 ch_RemoveAll(temp);
15134 cstring_Print(row.in, temp);
15135 str << " -in:";
15136 strptr_PrintBash(temp,str);
15137 }
15138 if (!(row.maxjobs == 2)) {
15139 ch_RemoveAll(temp);
15140 i32_Print(row.maxjobs, temp);
15141 str << " -maxjobs:";
15142 strptr_PrintBash(temp,str);
15143 }
15144 ch_RemoveAll(temp);
15145 i32_Print(row.ncmd, temp);
15146 str << " -ncmd:";
15147 strptr_PrintBash(temp,str);
15148}
15149
15150// --- command.atf_nrun..GetAnon
15151algo::strptr command::atf_nrun_GetAnon(command::atf_nrun &parent, i32 idx) {
15152 (void)parent;//only to avoid -Wunused-parameter
15153 switch(idx) {
15154 case(0): return strptr("ncmd", 4);
15155 default: return algo::strptr();
15156 }
15157}
15158
15159// --- command.atf_nrun..NArgs
15160// Used with command lines
15161// Return # of command-line arguments that must follow this argument
15162// If FIELD is invalid, return -1
15163i32 command::atf_nrun_NArgs(command::FieldId field, algo::strptr& out_dflt, bool* out_anon) {
15164 i32 retval = 1;
15165 switch (field) {
15166 case command_FieldId_in: { // $comment
15167 *out_anon = false;
15168 } break;
15169 case command_FieldId_maxjobs: { // $comment
15170 *out_anon = false;
15171 } break;
15172 case command_FieldId_ncmd: { // $comment
15173 *out_anon = true;
15174 } break;
15175 default:
15176 retval=-1; // unrecognized
15177 }
15178 (void)out_dflt;//only to avoid -Wunused-parameter
15179 return retval;
15180}
15181
15182// --- command.atf_nrun_proc.atf_nrun.Start
15183// Start subprocess
15184// If subprocess already running, do nothing. Otherwise, start it
15185int command::atf_nrun_Start(command::atf_nrun_proc& parent) {
15186 int retval = 0;
15187 if (parent.pid == 0) {
15188 verblog(atf_nrun_ToCmdline(parent)); // maybe print command
15189#ifdef WIN32
15190 algo_lib::ResolveExecFname(parent.path);
15191 tempstr cmdline(atf_nrun_ToCmdline(parent));
15192 parent.pid = dospawn(Zeroterm(parent.path),Zeroterm(cmdline),parent.timeout,parent.fstdin,parent.fstdout,parent.fstderr);
15193#else
15194 parent.pid = fork();
15195 if (parent.pid == 0) { // child
15196 algo_lib::DieWithParent();
15197 if (parent.timeout > 0) {
15198 alarm(parent.timeout);
15199 }
15200 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstdin , 0);
15201 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstdout, 1);
15202 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstderr, 2);
15203 if (retval==0) retval= atf_nrun_Execv(parent);
15204 if (retval != 0) { // if start fails, print error
15205 int err=errno;
15206 prerr("command.atf_nrun_execv"
15207 <<Keyval("errno",err)
15208 <<Keyval("errstr",strerror(err))
15209 <<Keyval("comment","Execv failed"));
15210 }
15211 _exit(127); // if failed to start, exit anyway
15212 } else if (parent.pid == -1) {
15213 retval = errno; // failed to fork
15214 }
15215#endif
15216 }
15217 parent.status = parent.pid > 0 ? 0 : -1; // if didn't start, set error status
15218 return retval;
15219}
15220
15221// --- command.atf_nrun_proc.atf_nrun.StartRead
15222// Start subprocess & Read output
15223algo::Fildes command::atf_nrun_StartRead(command::atf_nrun_proc& parent, algo_lib::FFildes &read) {
15224 int pipefd[2];
15225 int rc=pipe(pipefd);
15226 (void)rc;
15227 read.fd.value = pipefd[0];
15228 parent.fstdout << ">&" << pipefd[1];
15229 atf_nrun_Start(parent);
15230 (void)close(pipefd[1]);
15231 return read.fd;
15232}
15233
15234// --- command.atf_nrun_proc.atf_nrun.Kill
15235// Kill subprocess and wait
15236void command::atf_nrun_Kill(command::atf_nrun_proc& parent) {
15237 if (parent.pid != 0) {
15238 kill(parent.pid,9);
15239 atf_nrun_Wait(parent);
15240 }
15241}
15242
15243// --- command.atf_nrun_proc.atf_nrun.Wait
15244// Wait for subprocess to return
15245void command::atf_nrun_Wait(command::atf_nrun_proc& parent) {
15246 if (parent.pid > 0) {
15247 int wait_flags = 0;
15248 int wait_status = 0;
15249 int rc = -1;
15250 do {
15251 // really wait for subprocess to exit
15252 rc = waitpid(parent.pid,&wait_status,wait_flags);
15253 } while (rc==-1 && errno==EINTR);
15254 if (rc == parent.pid) {
15255 parent.status = wait_status;
15256 parent.pid = 0;
15257 }
15258 }
15259}
15260
15261// --- command.atf_nrun_proc.atf_nrun.Exec
15262// Start + Wait
15263// Execute subprocess and return exit code
15264int command::atf_nrun_Exec(command::atf_nrun_proc& parent) {
15265 atf_nrun_Start(parent);
15266 atf_nrun_Wait(parent);
15267 return parent.status;
15268}
15269
15270// --- command.atf_nrun_proc.atf_nrun.ExecX
15271// Start + Wait, throw exception on error
15272// Execute subprocess; throw human-readable exception on error
15273void command::atf_nrun_ExecX(command::atf_nrun_proc& parent) {
15274 int rc = atf_nrun_Exec(parent);
15275 vrfy(rc==0, tempstr() << "algo_lib.exec" << Keyval("cmd",atf_nrun_ToCmdline(parent))
15276 << Keyval("comment",algo::DescribeWaitStatus(parent.status)));
15277}
15278
15279// --- command.atf_nrun_proc.atf_nrun.Execv
15280// Call execv()
15281// Call execv with specified parameters
15282int command::atf_nrun_Execv(command::atf_nrun_proc& parent) {
15283 int ret = 0;
15284 algo::StringAry args;
15285 atf_nrun_ToArgv(parent, args);
15286 char **argv = (char**)alloca((ary_N(args)+1)*sizeof(*argv));
15287 ind_beg(algo::StringAry_ary_curs,arg,args) {
15288 argv[ind_curs(arg).index] = Zeroterm(arg);
15289 }ind_end;
15290 argv[ary_N(args)] = NULL;
15291 // if parent.path is relative, search for it in PATH
15292 algo_lib::ResolveExecFname(parent.path);
15293 ret = execv(Zeroterm(parent.path),argv);
15294 return ret;
15295}
15296
15297// --- command.atf_nrun_proc.atf_nrun.ToCmdline
15298algo::tempstr command::atf_nrun_ToCmdline(command::atf_nrun_proc& parent) {
15299 algo::tempstr retval;
15300 retval << parent.path << " ";
15301 command::atf_nrun_PrintArgv(parent.cmd,retval);
15302 if (ch_N(parent.fstdin)) {
15303 retval << " " << parent.fstdin;
15304 }
15305 if (ch_N(parent.fstdout)) {
15306 retval << " " << parent.fstdout;
15307 }
15308 if (ch_N(parent.fstderr)) {
15309 retval << " 2" << parent.fstderr;
15310 }
15311 return retval;
15312}
15313
15314// --- command.atf_nrun_proc.atf_nrun.ToArgv
15315// Form array from the command line
15316void command::atf_nrun_ToArgv(command::atf_nrun_proc& parent, algo::StringAry& args) {
15317 ary_RemoveAll(args);
15318 ary_Alloc(args) << parent.path;
15319
15320 if (parent.cmd.in != "data") {
15321 cstring *arg = &ary_Alloc(args);
15322 *arg << "-in:";
15323 cstring_Print(parent.cmd.in, *arg);
15324 }
15325
15326 if (parent.cmd.maxjobs != 2) {
15327 cstring *arg = &ary_Alloc(args);
15328 *arg << "-maxjobs:";
15329 i32_Print(parent.cmd.maxjobs, *arg);
15330 }
15331
15332 if (parent.cmd.ncmd != 6) {
15333 cstring *arg = &ary_Alloc(args);
15334 *arg << "-ncmd:";
15335 i32_Print(parent.cmd.ncmd, *arg);
15336 }
15337 for (int i=1; i < algo_lib::_db.cmdline.verbose; ++i) {
15338 ary_Alloc(args) << "-verbose";
15339 }
15340}
15341
15342// --- command.atf_nrun_proc..Uninit
15343void command::atf_nrun_proc_Uninit(command::atf_nrun_proc& parent) {
15344 command::atf_nrun_proc &row = parent; (void)row;
15345
15346 // command.atf_nrun_proc.atf_nrun.Uninit (Exec) //
15347 atf_nrun_Kill(parent); // kill child, ensure forward progress
15348}
15349
15350// --- command.atf_unit.unittest.Print
15351// Print back to string
15352void command::unittest_Print(command::atf_unit& parent, algo::cstring &out) {
15353 Regx_Print(parent.unittest, out);
15354}
15355
15356// --- command.atf_unit.unittest.ReadStrptrMaybe
15357// Read Regx from string
15358// Convert string to field. Return success value
15359bool command::unittest_ReadStrptrMaybe(command::atf_unit& parent, algo::strptr in) {
15360 bool retval = true;
15361 Regx_ReadSql(parent.unittest, in, true);
15362 return retval;
15363}
15364
15365// --- command.atf_unit..ReadFieldMaybe
15366bool command::atf_unit_ReadFieldMaybe(command::atf_unit& parent, algo::strptr field, algo::strptr strval) {
15367 bool retval = true;
15368 command::FieldId field_id;
15369 (void)value_SetStrptrMaybe(field_id,field);
15370 switch(field_id) {
15371 case command_FieldId_unittest: {
15372 retval = unittest_ReadStrptrMaybe(parent, strval);
15373 break;
15374 }
15375 case command_FieldId_nofork: {
15376 retval = bool_ReadStrptrMaybe(parent.nofork, strval);
15377 break;
15378 }
15379 case command_FieldId_arg: {
15380 retval = algo::cstring_ReadStrptrMaybe(parent.arg, strval);
15381 break;
15382 }
15383 case command_FieldId_data_dir: {
15384 retval = algo::cstring_ReadStrptrMaybe(parent.data_dir, strval);
15385 break;
15386 }
15387 case command_FieldId_mdbg: {
15388 retval = bool_ReadStrptrMaybe(parent.mdbg, strval);
15389 break;
15390 }
15391 case command_FieldId_perf_secs: {
15392 retval = double_ReadStrptrMaybe(parent.perf_secs, strval);
15393 break;
15394 }
15395 case command_FieldId_pertest_timeout: {
15396 retval = u32_ReadStrptrMaybe(parent.pertest_timeout, strval);
15397 break;
15398 }
15399 case command_FieldId_report: {
15400 retval = bool_ReadStrptrMaybe(parent.report, strval);
15401 break;
15402 }
15403 case command_FieldId_capture: {
15404 retval = bool_ReadStrptrMaybe(parent.capture, strval);
15405 break;
15406 }
15407 case command_FieldId_check_untracked: {
15408 retval = bool_ReadStrptrMaybe(parent.check_untracked, strval);
15409 break;
15410 }
15411 default: break;
15412 }
15413 if (!retval) {
15414 algo_lib::AppendErrtext("attr",field);
15415 }
15416 return retval;
15417}
15418
15419// --- command.atf_unit..ReadTupleMaybe
15420// Read fields of command::atf_unit from attributes of ascii tuple TUPLE
15421bool command::atf_unit_ReadTupleMaybe(command::atf_unit &parent, algo::Tuple &tuple) {
15422 bool retval = true;
15423 int anon_idx = 0;
15424 ind_beg(algo::Tuple_attrs_curs,attr,tuple) {
15425 if (ch_N(attr.name) == 0) {
15426 attr.name = atf_unit_GetAnon(parent, anon_idx++);
15427 }
15428 retval = atf_unit_ReadFieldMaybe(parent, attr.name, attr.value);
15429 if (!retval) {
15430 break;
15431 }
15432 }ind_end;
15433 return retval;
15434}
15435
15436// --- command.atf_unit..Init
15437// Set all fields to initial values.
15438void command::atf_unit_Init(command::atf_unit& parent) {
15439 Regx_ReadSql(parent.unittest, "%", true);
15440 parent.nofork = bool(false);
15441 parent.arg = algo::strptr("");
15442 parent.data_dir = algo::strptr("data");
15443 parent.mdbg = bool(0);
15444 parent.perf_secs = double(1.0);
15445 parent.pertest_timeout = u32(900);
15446 parent.report = bool(true);
15447 parent.capture = bool(false);
15448 parent.check_untracked = bool(true);
15449}
15450
15451// --- command.atf_unit..ToCmdline
15452// Convenience function that returns a full command line
15453// Assume command is in a directory called bin
15454tempstr command::atf_unit_ToCmdline(command::atf_unit& row) {
15455 tempstr ret;
15456 ret << "bin/atf_unit ";
15457 atf_unit_PrintArgv(row, ret);
15458 // inherit less intense verbose, debug options
15459 for (int i = 1; i < algo_lib::_db.cmdline.verbose; i++) {
15460 ret << " -verbose";
15461 }
15462 for (int i = 1; i < algo_lib::_db.cmdline.debug; i++) {
15463 ret << " -debug";
15464 }
15465 return ret;
15466}
15467
15468// --- command.atf_unit..PrintArgv
15469// print string representation of ROW to string STR
15470// cfmt:command.atf_unit.Argv printfmt:Auto
15471void command::atf_unit_PrintArgv(command::atf_unit& row, algo::cstring& str) {
15472 algo::tempstr temp;
15473 (void)temp;
15474 (void)str;
15475 ch_RemoveAll(temp);
15476 command::unittest_Print(const_cast<command::atf_unit&>(row), temp);
15477 str << " -unittest:";
15478 strptr_PrintBash(temp,str);
15479 if (!(row.nofork == false)) {
15480 ch_RemoveAll(temp);
15481 bool_Print(row.nofork, temp);
15482 str << " -nofork:";
15483 strptr_PrintBash(temp,str);
15484 }
15485 if (!(row.arg == "")) {
15486 ch_RemoveAll(temp);
15487 cstring_Print(row.arg, temp);
15488 str << " -arg:";
15489 strptr_PrintBash(temp,str);
15490 }
15491 if (!(row.data_dir == "data")) {
15492 ch_RemoveAll(temp);
15493 cstring_Print(row.data_dir, temp);
15494 str << " -data_dir:";
15495 strptr_PrintBash(temp,str);
15496 }
15497 if (!(row.mdbg == 0)) {
15498 ch_RemoveAll(temp);
15499 bool_Print(row.mdbg, temp);
15500 str << " -mdbg:";
15501 strptr_PrintBash(temp,str);
15502 }
15503 if (!(row.perf_secs == 1.0)) {
15504 ch_RemoveAll(temp);
15505 double_Print(row.perf_secs, temp);
15506 str << " -perf_secs:";
15507 strptr_PrintBash(temp,str);
15508 }
15509 if (!(row.pertest_timeout == 900)) {
15510 ch_RemoveAll(temp);
15511 u32_Print(row.pertest_timeout, temp);
15512 str << " -pertest_timeout:";
15513 strptr_PrintBash(temp,str);
15514 }
15515 if (!(row.report == true)) {
15516 ch_RemoveAll(temp);
15517 bool_Print(row.report, temp);
15518 str << " -report:";
15519 strptr_PrintBash(temp,str);
15520 }
15521 if (!(row.capture == false)) {
15522 ch_RemoveAll(temp);
15523 bool_Print(row.capture, temp);
15524 str << " -capture:";
15525 strptr_PrintBash(temp,str);
15526 }
15527 if (!(row.check_untracked == true)) {
15528 ch_RemoveAll(temp);
15529 bool_Print(row.check_untracked, temp);
15530 str << " -check_untracked:";
15531 strptr_PrintBash(temp,str);
15532 }
15533}
15534
15535// --- command.atf_unit..GetAnon
15536algo::strptr command::atf_unit_GetAnon(command::atf_unit &parent, i32 idx) {
15537 (void)parent;//only to avoid -Wunused-parameter
15538 switch(idx) {
15539 case(0): return strptr("unittest", 8);
15540 default: return algo::strptr();
15541 }
15542}
15543
15544// --- command.atf_unit..NArgs
15545// Used with command lines
15546// Return # of command-line arguments that must follow this argument
15547// If FIELD is invalid, return -1
15548i32 command::atf_unit_NArgs(command::FieldId field, algo::strptr& out_dflt, bool* out_anon) {
15549 i32 retval = 1;
15550 switch (field) {
15551 case command_FieldId_unittest: { // $comment
15552 *out_anon = true;
15553 } break;
15554 case command_FieldId_nofork: { // $comment
15555 *out_anon = false;
15556 retval=0;
15557 out_dflt="Y";
15558 } break;
15559 case command_FieldId_arg: { // bool: no argument required but value may be specified as nofork:Y
15560 *out_anon = false;
15561 } break;
15562 case command_FieldId_data_dir: { // bool: no argument required but value may be specified as nofork:Y
15563 *out_anon = false;
15564 } break;
15565 case command_FieldId_mdbg: { // bool: no argument required but value may be specified as nofork:Y
15566 *out_anon = false;
15567 retval=0;
15568 out_dflt="Y";
15569 } break;
15570 case command_FieldId_perf_secs: { // bool: no argument required but value may be specified as mdbg:Y
15571 *out_anon = false;
15572 } break;
15573 case command_FieldId_pertest_timeout: { // bool: no argument required but value may be specified as mdbg:Y
15574 *out_anon = false;
15575 } break;
15576 case command_FieldId_report: { // bool: no argument required but value may be specified as mdbg:Y
15577 *out_anon = false;
15578 retval=0;
15579 out_dflt="Y";
15580 } break;
15581 case command_FieldId_capture: { // bool: no argument required but value may be specified as report:Y
15582 *out_anon = false;
15583 retval=0;
15584 out_dflt="Y";
15585 } break;
15586 case command_FieldId_check_untracked: { // bool: no argument required but value may be specified as capture:Y
15587 *out_anon = false;
15588 retval=0;
15589 out_dflt="Y";
15590 } break;
15591 default:
15592 retval=-1; // unrecognized
15593 }
15594 return retval;
15595}
15596
15597// --- command.atf_unit_proc.atf_unit.Start
15598// Start subprocess
15599// If subprocess already running, do nothing. Otherwise, start it
15600int command::atf_unit_Start(command::atf_unit_proc& parent) {
15601 int retval = 0;
15602 if (parent.pid == 0) {
15603 verblog(atf_unit_ToCmdline(parent)); // maybe print command
15604#ifdef WIN32
15605 algo_lib::ResolveExecFname(parent.path);
15606 tempstr cmdline(atf_unit_ToCmdline(parent));
15607 parent.pid = dospawn(Zeroterm(parent.path),Zeroterm(cmdline),parent.timeout,parent.fstdin,parent.fstdout,parent.fstderr);
15608#else
15609 parent.pid = fork();
15610 if (parent.pid == 0) { // child
15611 algo_lib::DieWithParent();
15612 if (parent.timeout > 0) {
15613 alarm(parent.timeout);
15614 }
15615 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstdin , 0);
15616 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstdout, 1);
15617 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstderr, 2);
15618 if (retval==0) retval= atf_unit_Execv(parent);
15619 if (retval != 0) { // if start fails, print error
15620 int err=errno;
15621 prerr("command.atf_unit_execv"
15622 <<Keyval("errno",err)
15623 <<Keyval("errstr",strerror(err))
15624 <<Keyval("comment","Execv failed"));
15625 }
15626 _exit(127); // if failed to start, exit anyway
15627 } else if (parent.pid == -1) {
15628 retval = errno; // failed to fork
15629 }
15630#endif
15631 }
15632 parent.status = parent.pid > 0 ? 0 : -1; // if didn't start, set error status
15633 return retval;
15634}
15635
15636// --- command.atf_unit_proc.atf_unit.StartRead
15637// Start subprocess & Read output
15638algo::Fildes command::atf_unit_StartRead(command::atf_unit_proc& parent, algo_lib::FFildes &read) {
15639 int pipefd[2];
15640 int rc=pipe(pipefd);
15641 (void)rc;
15642 read.fd.value = pipefd[0];
15643 parent.fstdout << ">&" << pipefd[1];
15644 atf_unit_Start(parent);
15645 (void)close(pipefd[1]);
15646 return read.fd;
15647}
15648
15649// --- command.atf_unit_proc.atf_unit.Kill
15650// Kill subprocess and wait
15651void command::atf_unit_Kill(command::atf_unit_proc& parent) {
15652 if (parent.pid != 0) {
15653 kill(parent.pid,9);
15654 atf_unit_Wait(parent);
15655 }
15656}
15657
15658// --- command.atf_unit_proc.atf_unit.Wait
15659// Wait for subprocess to return
15660void command::atf_unit_Wait(command::atf_unit_proc& parent) {
15661 if (parent.pid > 0) {
15662 int wait_flags = 0;
15663 int wait_status = 0;
15664 int rc = -1;
15665 do {
15666 // really wait for subprocess to exit
15667 rc = waitpid(parent.pid,&wait_status,wait_flags);
15668 } while (rc==-1 && errno==EINTR);
15669 if (rc == parent.pid) {
15670 parent.status = wait_status;
15671 parent.pid = 0;
15672 }
15673 }
15674}
15675
15676// --- command.atf_unit_proc.atf_unit.Exec
15677// Start + Wait
15678// Execute subprocess and return exit code
15679int command::atf_unit_Exec(command::atf_unit_proc& parent) {
15680 atf_unit_Start(parent);
15681 atf_unit_Wait(parent);
15682 return parent.status;
15683}
15684
15685// --- command.atf_unit_proc.atf_unit.ExecX
15686// Start + Wait, throw exception on error
15687// Execute subprocess; throw human-readable exception on error
15688void command::atf_unit_ExecX(command::atf_unit_proc& parent) {
15689 int rc = atf_unit_Exec(parent);
15690 vrfy(rc==0, tempstr() << "algo_lib.exec" << Keyval("cmd",atf_unit_ToCmdline(parent))
15691 << Keyval("comment",algo::DescribeWaitStatus(parent.status)));
15692}
15693
15694// --- command.atf_unit_proc.atf_unit.Execv
15695// Call execv()
15696// Call execv with specified parameters
15697int command::atf_unit_Execv(command::atf_unit_proc& parent) {
15698 int ret = 0;
15699 algo::StringAry args;
15700 atf_unit_ToArgv(parent, args);
15701 char **argv = (char**)alloca((ary_N(args)+1)*sizeof(*argv));
15702 ind_beg(algo::StringAry_ary_curs,arg,args) {
15703 argv[ind_curs(arg).index] = Zeroterm(arg);
15704 }ind_end;
15705 argv[ary_N(args)] = NULL;
15706 // if parent.path is relative, search for it in PATH
15707 algo_lib::ResolveExecFname(parent.path);
15708 ret = execv(Zeroterm(parent.path),argv);
15709 return ret;
15710}
15711
15712// --- command.atf_unit_proc.atf_unit.ToCmdline
15713algo::tempstr command::atf_unit_ToCmdline(command::atf_unit_proc& parent) {
15714 algo::tempstr retval;
15715 retval << parent.path << " ";
15716 command::atf_unit_PrintArgv(parent.cmd,retval);
15717 if (ch_N(parent.fstdin)) {
15718 retval << " " << parent.fstdin;
15719 }
15720 if (ch_N(parent.fstdout)) {
15721 retval << " " << parent.fstdout;
15722 }
15723 if (ch_N(parent.fstderr)) {
15724 retval << " 2" << parent.fstderr;
15725 }
15726 return retval;
15727}
15728
15729// --- command.atf_unit_proc.atf_unit.ToArgv
15730// Form array from the command line
15731void command::atf_unit_ToArgv(command::atf_unit_proc& parent, algo::StringAry& args) {
15732 ary_RemoveAll(args);
15733 ary_Alloc(args) << parent.path;
15734
15735 if (parent.cmd.unittest.expr != "%") {
15736 cstring *arg = &ary_Alloc(args);
15737 *arg << "-unittest:";
15738 command::unittest_Print(parent.cmd, *arg);
15739 }
15740
15741 if (parent.cmd.nofork != false) {
15742 cstring *arg = &ary_Alloc(args);
15743 *arg << "-nofork:";
15744 bool_Print(parent.cmd.nofork, *arg);
15745 }
15746
15747 if (parent.cmd.arg != "") {
15748 cstring *arg = &ary_Alloc(args);
15749 *arg << "-arg:";
15750 cstring_Print(parent.cmd.arg, *arg);
15751 }
15752
15753 if (parent.cmd.data_dir != "data") {
15754 cstring *arg = &ary_Alloc(args);
15755 *arg << "-data_dir:";
15756 cstring_Print(parent.cmd.data_dir, *arg);
15757 }
15758
15759 if (parent.cmd.mdbg != 0) {
15760 cstring *arg = &ary_Alloc(args);
15761 *arg << "-mdbg:";
15762 bool_Print(parent.cmd.mdbg, *arg);
15763 }
15764
15765 if (parent.cmd.perf_secs != 1.0) {
15766 cstring *arg = &ary_Alloc(args);
15767 *arg << "-perf_secs:";
15768 double_Print(parent.cmd.perf_secs, *arg);
15769 }
15770
15771 if (parent.cmd.pertest_timeout != 900) {
15772 cstring *arg = &ary_Alloc(args);
15773 *arg << "-pertest_timeout:";
15774 u32_Print(parent.cmd.pertest_timeout, *arg);
15775 }
15776
15777 if (parent.cmd.report != true) {
15778 cstring *arg = &ary_Alloc(args);
15779 *arg << "-report:";
15780 bool_Print(parent.cmd.report, *arg);
15781 }
15782
15783 if (parent.cmd.capture != false) {
15784 cstring *arg = &ary_Alloc(args);
15785 *arg << "-capture:";
15786 bool_Print(parent.cmd.capture, *arg);
15787 }
15788
15789 if (parent.cmd.check_untracked != true) {
15790 cstring *arg = &ary_Alloc(args);
15791 *arg << "-check_untracked:";
15792 bool_Print(parent.cmd.check_untracked, *arg);
15793 }
15794 for (int i=1; i < algo_lib::_db.cmdline.verbose; ++i) {
15795 ary_Alloc(args) << "-verbose";
15796 }
15797}
15798
15799// --- command.atf_unit_proc..Uninit
15800void command::atf_unit_proc_Uninit(command::atf_unit_proc& parent) {
15801 command::atf_unit_proc &row = parent; (void)row;
15802
15803 // command.atf_unit_proc.atf_unit.Uninit (Exec) //
15804 atf_unit_Kill(parent); // kill child, ensure forward progress
15805}
15806
15807// --- command.atf_wcli.wtblacttst.Print
15808// Print back to string
15809void command::wtblacttst_Print(command::atf_wcli& parent, algo::cstring &out) {
15810 Regx_Print(parent.wtblacttst, out);
15811}
15812
15813// --- command.atf_wcli.wtblacttst.ReadStrptrMaybe
15814// Read Regx from string
15815// Convert string to field. Return success value
15816bool command::wtblacttst_ReadStrptrMaybe(command::atf_wcli& parent, algo::strptr in) {
15817 bool retval = true;
15818 Regx_ReadSql(parent.wtblacttst, in, true);
15819 return retval;
15820}
15821
15822// --- command.atf_wcli.wiki_update_fields.Addary
15823// Reserve space (this may move memory). Insert N element at the end.
15824// Return aryptr to newly inserted block.
15825// If the RHS argument aliases the array (refers to the same memory), exit program with fatal error.
15826algo::aryptr<algo::cstring> command::wiki_update_fields_Addary(command::atf_wcli& parent, algo::aryptr<algo::cstring> rhs) {
15827 bool overlaps = rhs.n_elems>0 && rhs.elems >= parent.wiki_update_fields_elems && rhs.elems < parent.wiki_update_fields_elems + parent.wiki_update_fields_max;
15828 if (UNLIKELY(overlaps)) {
15829 FatalErrorExit("command.tary_alias field:command.atf_wcli.wiki_update_fields comment:'alias error: sub-array is being appended to the whole'");
15830 }
15831 int nnew = rhs.n_elems;
15832 wiki_update_fields_Reserve(parent, nnew); // reserve space
15833 int at = parent.wiki_update_fields_n;
15834 for (int i = 0; i < nnew; i++) {
15835 new (parent.wiki_update_fields_elems + at + i) algo::cstring(rhs[i]);
15836 parent.wiki_update_fields_n++;
15837 }
15838 return algo::aryptr<algo::cstring>(parent.wiki_update_fields_elems + at, nnew);
15839}
15840
15841// --- command.atf_wcli.wiki_update_fields.Alloc
15842// Reserve space. Insert element at the end
15843// The new element is initialized to a default value
15844algo::cstring& command::wiki_update_fields_Alloc(command::atf_wcli& parent) {
15845 wiki_update_fields_Reserve(parent, 1);
15846 int n = parent.wiki_update_fields_n;
15847 int at = n;
15848 algo::cstring *elems = parent.wiki_update_fields_elems;
15849 new (elems + at) algo::cstring(""); // construct new element, default initializer
15850 parent.wiki_update_fields_n = n+1;
15851 return elems[at];
15852}
15853
15854// --- command.atf_wcli.wiki_update_fields.AllocAt
15855// Reserve space for new element, reallocating the array if necessary
15856// Insert new element at specified index. Index must be in range or a fatal error occurs.
15857algo::cstring& command::wiki_update_fields_AllocAt(command::atf_wcli& parent, int at) {
15858 wiki_update_fields_Reserve(parent, 1);
15859 int n = parent.wiki_update_fields_n;
15860 if (UNLIKELY(u64(at) >= u64(n+1))) {
15861 FatalErrorExit("command.bad_alloc_at field:command.atf_wcli.wiki_update_fields comment:'index out of range'");
15862 }
15863 algo::cstring *elems = parent.wiki_update_fields_elems;
15864 memmove(elems + at + 1, elems + at, (n - at) * sizeof(algo::cstring));
15865 new (elems + at) algo::cstring(""); // construct element, default initializer
15866 parent.wiki_update_fields_n = n+1;
15867 return elems[at];
15868}
15869
15870// --- command.atf_wcli.wiki_update_fields.AllocN
15871// Reserve space. Insert N elements at the end of the array, return pointer to array
15872algo::aryptr<algo::cstring> command::wiki_update_fields_AllocN(command::atf_wcli& parent, int n_elems) {
15873 wiki_update_fields_Reserve(parent, n_elems);
15874 int old_n = parent.wiki_update_fields_n;
15875 int new_n = old_n + n_elems;
15876 algo::cstring *elems = parent.wiki_update_fields_elems;
15877 for (int i = old_n; i < new_n; i++) {
15878 new (elems + i) algo::cstring(""); // construct new element, default initialize
15879 }
15880 parent.wiki_update_fields_n = new_n;
15881 return algo::aryptr<algo::cstring>(elems + old_n, n_elems);
15882}
15883
15884// --- command.atf_wcli.wiki_update_fields.Remove
15885// Remove item by index. If index outside of range, do nothing.
15886void command::wiki_update_fields_Remove(command::atf_wcli& parent, u32 i) {
15887 u32 lim = parent.wiki_update_fields_n;
15888 algo::cstring *elems = parent.wiki_update_fields_elems;
15889 if (i < lim) {
15890 elems[i].~cstring(); // destroy element
15891 memmove(elems + i, elems + (i + 1), sizeof(algo::cstring) * (lim - (i + 1)));
15892 parent.wiki_update_fields_n = lim - 1;
15893 }
15894}
15895
15896// --- command.atf_wcli.wiki_update_fields.RemoveAll
15897void command::wiki_update_fields_RemoveAll(command::atf_wcli& parent) {
15898 u32 n = parent.wiki_update_fields_n;
15899 while (n > 0) {
15900 n -= 1;
15901 parent.wiki_update_fields_elems[n].~cstring();
15902 parent.wiki_update_fields_n = n;
15903 }
15904}
15905
15906// --- command.atf_wcli.wiki_update_fields.RemoveLast
15907// Delete last element of array. Do nothing if array is empty.
15908void command::wiki_update_fields_RemoveLast(command::atf_wcli& parent) {
15909 u64 n = parent.wiki_update_fields_n;
15910 if (n > 0) {
15911 n -= 1;
15912 wiki_update_fields_qFind(parent, u64(n)).~cstring();
15913 parent.wiki_update_fields_n = n;
15914 }
15915}
15916
15917// --- command.atf_wcli.wiki_update_fields.AbsReserve
15918// Make sure N elements fit in array. Process dies if out of memory
15919void command::wiki_update_fields_AbsReserve(command::atf_wcli& parent, int n) {
15920 u32 old_max = parent.wiki_update_fields_max;
15921 if (n > i32(old_max)) {
15922 u32 new_max = i32_Max(i32_Max(old_max * 2, n), 4);
15923 void *new_mem = algo_lib::malloc_ReallocMem(parent.wiki_update_fields_elems, old_max * sizeof(algo::cstring), new_max * sizeof(algo::cstring));
15924 if (UNLIKELY(!new_mem)) {
15925 FatalErrorExit("command.tary_nomem field:command.atf_wcli.wiki_update_fields comment:'out of memory'");
15926 }
15927 parent.wiki_update_fields_elems = (algo::cstring*)new_mem;
15928 parent.wiki_update_fields_max = new_max;
15929 }
15930}
15931
15932// --- command.atf_wcli.wiki_update_fields.Setary
15933// Copy contents of RHS to PARENT.
15934void command::wiki_update_fields_Setary(command::atf_wcli& parent, command::atf_wcli &rhs) {
15935 wiki_update_fields_RemoveAll(parent);
15936 int nnew = rhs.wiki_update_fields_n;
15937 wiki_update_fields_Reserve(parent, nnew); // reserve space
15938 for (int i = 0; i < nnew; i++) { // copy elements over
15939 new (parent.wiki_update_fields_elems + i) algo::cstring(wiki_update_fields_qFind(rhs, i));
15940 parent.wiki_update_fields_n = i + 1;
15941 }
15942}
15943
15944// --- command.atf_wcli.wiki_update_fields.Setary2
15945// Copy specified array into wiki_update_fields, discarding previous contents.
15946// If the RHS argument aliases the array (refers to the same memory), throw exception.
15947void command::wiki_update_fields_Setary(command::atf_wcli& parent, const algo::aryptr<algo::cstring> &rhs) {
15948 wiki_update_fields_RemoveAll(parent);
15949 wiki_update_fields_Addary(parent, rhs);
15950}
15951
15952// --- command.atf_wcli.wiki_update_fields.AllocNVal
15953// Reserve space. Insert N elements at the end of the array, return pointer to array
15954algo::aryptr<algo::cstring> command::wiki_update_fields_AllocNVal(command::atf_wcli& parent, int n_elems, const algo::cstring& val) {
15955 wiki_update_fields_Reserve(parent, n_elems);
15956 int old_n = parent.wiki_update_fields_n;
15957 int new_n = old_n + n_elems;
15958 algo::cstring *elems = parent.wiki_update_fields_elems;
15959 for (int i = old_n; i < new_n; i++) {
15960 new (elems + i) algo::cstring(val);
15961 }
15962 parent.wiki_update_fields_n = new_n;
15963 return algo::aryptr<algo::cstring>(elems + old_n, n_elems);
15964}
15965
15966// --- command.atf_wcli.wiki_update_fields.ReadStrptrMaybe
15967// A single element is read from input string and appended to the array.
15968// If the string contains an error, the array is untouched.
15969// Function returns success value.
15970bool command::wiki_update_fields_ReadStrptrMaybe(command::atf_wcli& parent, algo::strptr in_str) {
15971 bool retval = true;
15972 algo::cstring &elem = wiki_update_fields_Alloc(parent);
15973 retval = algo::cstring_ReadStrptrMaybe(elem, in_str);
15974 if (!retval) {
15975 wiki_update_fields_RemoveLast(parent);
15976 }
15977 return retval;
15978}
15979
15980// --- command.atf_wcli..ReadFieldMaybe
15981bool command::atf_wcli_ReadFieldMaybe(command::atf_wcli& parent, algo::strptr field, algo::strptr strval) {
15982 bool retval = true;
15983 command::FieldId field_id;
15984 (void)value_SetStrptrMaybe(field_id,algo::Pathcomp(field, ".LL"));
15985 switch(field_id) {
15986 case command_FieldId_capture: {
15987 retval = bool_ReadStrptrMaybe(parent.capture, strval);
15988 break;
15989 }
15990 case command_FieldId_wtblacttst: {
15991 retval = wtblacttst_ReadStrptrMaybe(parent, strval);
15992 break;
15993 }
15994 case command_FieldId_in: {
15995 retval = algo::cstring_ReadStrptrMaybe(parent.in, strval);
15996 break;
15997 }
15998 case command_FieldId_wiki_envnode: {
15999 retval = algo::Smallstr50_ReadStrptrMaybe(parent.wiki_envnode, strval);
16000 break;
16001 }
16002 case command_FieldId_wiki_kill: {
16003 retval = bool_ReadStrptrMaybe(parent.wiki_kill, strval);
16004 break;
16005 }
16006 case command_FieldId_wiki_start: {
16007 retval = bool_ReadStrptrMaybe(parent.wiki_start, strval);
16008 break;
16009 }
16010 case command_FieldId_wiki_update: {
16011 retval = bool_ReadStrptrMaybe(parent.wiki_update, strval);
16012 break;
16013 }
16014 case command_FieldId_wiki_update_help: {
16015 retval = bool_ReadStrptrMaybe(parent.wiki_update_help, strval);
16016 break;
16017 }
16018 case command_FieldId_wiki_update_fields: {
16019 retval = wiki_update_fields_ReadStrptrMaybe(parent, strval);
16020 break;
16021 }
16022 case command_FieldId_wiki_clean_start: {
16023 retval = bool_ReadStrptrMaybe(parent.wiki_clean_start, strval);
16024 break;
16025 }
16026 case command_FieldId_authdir_dflt: {
16027 retval = bool_ReadStrptrMaybe(parent.authdir_dflt, strval);
16028 break;
16029 }
16030 case command_FieldId_dry_run: {
16031 retval = bool_ReadStrptrMaybe(parent.dry_run, strval);
16032 break;
16033 }
16034 case command_FieldId_wikisite: {
16035 retval = algo::Smallstr50_ReadStrptrMaybe(parent.wikisite, strval);
16036 break;
16037 }
16038 default: break;
16039 }
16040 if (!retval) {
16041 algo_lib::AppendErrtext("attr",field);
16042 }
16043 return retval;
16044}
16045
16046// --- command.atf_wcli..ReadTupleMaybe
16047// Read fields of command::atf_wcli from attributes of ascii tuple TUPLE
16048bool command::atf_wcli_ReadTupleMaybe(command::atf_wcli &parent, algo::Tuple &tuple) {
16049 bool retval = true;
16050 int anon_idx = 0;
16051 ind_beg(algo::Tuple_attrs_curs,attr,tuple) {
16052 if (ch_N(attr.name) == 0) {
16053 attr.name = atf_wcli_GetAnon(parent, anon_idx++);
16054 }
16055 retval = atf_wcli_ReadFieldMaybe(parent, attr.name, attr.value);
16056 if (!retval) {
16057 break;
16058 }
16059 }ind_end;
16060 return retval;
16061}
16062
16063// --- command.atf_wcli..Init
16064// Set all fields to initial values.
16065void command::atf_wcli_Init(command::atf_wcli& parent) {
16066 parent.capture = bool(false);
16067 Regx_ReadSql(parent.wtblacttst, "", true);
16068 parent.in = algo::strptr("data");
16069 parent.wiki_envnode = algo::strptr("dev.wiki-qa1-nyc0");
16070 parent.wiki_kill = bool(false);
16071 parent.wiki_start = bool(false);
16072 parent.wiki_update = bool(false);
16073 parent.wiki_update_help = bool(false);
16074 parent.wiki_update_fields_elems = 0; // (command.atf_wcli.wiki_update_fields)
16075 parent.wiki_update_fields_n = 0; // (command.atf_wcli.wiki_update_fields)
16076 parent.wiki_update_fields_max = 0; // (command.atf_wcli.wiki_update_fields)
16077 parent.wiki_clean_start = bool(false);
16078 parent.authdir_dflt = bool(false);
16079 parent.dry_run = bool(false);
16080 parent.wikisite = algo::strptr("Openacr");
16081}
16082
16083// --- command.atf_wcli..Uninit
16084void command::atf_wcli_Uninit(command::atf_wcli& parent) {
16085 command::atf_wcli &row = parent; (void)row;
16086
16087 // command.atf_wcli.wiki_update_fields.Uninit (Tary) //additional key:value pairs for use with -wiki_update, see -wiki_update_help
16088 // remove all elements from command.atf_wcli.wiki_update_fields
16089 wiki_update_fields_RemoveAll(parent);
16090 // free memory for Tary command.atf_wcli.wiki_update_fields
16091 algo_lib::malloc_FreeMem(parent.wiki_update_fields_elems, sizeof(algo::cstring)*parent.wiki_update_fields_max); // (command.atf_wcli.wiki_update_fields)
16092}
16093
16094// --- command.atf_wcli..ToCmdline
16095// Convenience function that returns a full command line
16096// Assume command is in a directory called bin
16097tempstr command::atf_wcli_ToCmdline(command::atf_wcli& row) {
16098 tempstr ret;
16099 ret << "bin/atf_wcli ";
16100 atf_wcli_PrintArgv(row, ret);
16101 // inherit less intense verbose, debug options
16102 for (int i = 1; i < algo_lib::_db.cmdline.verbose; i++) {
16103 ret << " -verbose";
16104 }
16105 for (int i = 1; i < algo_lib::_db.cmdline.debug; i++) {
16106 ret << " -debug";
16107 }
16108 return ret;
16109}
16110
16111// --- command.atf_wcli..PrintArgv
16112// print string representation of ROW to string STR
16113// cfmt:command.atf_wcli.Argv printfmt:Tuple
16114void command::atf_wcli_PrintArgv(command::atf_wcli& row, algo::cstring& str) {
16115 algo::tempstr temp;
16116 (void)temp;
16117 (void)str;
16118 if (!(row.capture == false)) {
16119 ch_RemoveAll(temp);
16120 bool_Print(row.capture, temp);
16121 str << " -capture:";
16122 strptr_PrintBash(temp,str);
16123 }
16124 if (!(row.wtblacttst.expr == "")) {
16125 ch_RemoveAll(temp);
16126 command::wtblacttst_Print(const_cast<command::atf_wcli&>(row), temp);
16127 str << " -wtblacttst:";
16128 strptr_PrintBash(temp,str);
16129 }
16130 if (!(row.in == "data")) {
16131 ch_RemoveAll(temp);
16132 cstring_Print(row.in, temp);
16133 str << " -in:";
16134 strptr_PrintBash(temp,str);
16135 }
16136 if (!(row.wiki_envnode == "dev.wiki-qa1-nyc0")) {
16137 ch_RemoveAll(temp);
16138 Smallstr50_Print(row.wiki_envnode, temp);
16139 str << " -wiki_envnode:";
16140 strptr_PrintBash(temp,str);
16141 }
16142 if (!(row.wiki_kill == false)) {
16143 ch_RemoveAll(temp);
16144 bool_Print(row.wiki_kill, temp);
16145 str << " -wiki_kill:";
16146 strptr_PrintBash(temp,str);
16147 }
16148 if (!(row.wiki_start == false)) {
16149 ch_RemoveAll(temp);
16150 bool_Print(row.wiki_start, temp);
16151 str << " -wiki_start:";
16152 strptr_PrintBash(temp,str);
16153 }
16154 if (!(row.wiki_update == false)) {
16155 ch_RemoveAll(temp);
16156 bool_Print(row.wiki_update, temp);
16157 str << " -wiki_update:";
16158 strptr_PrintBash(temp,str);
16159 }
16160 if (!(row.wiki_update_help == false)) {
16161 ch_RemoveAll(temp);
16162 bool_Print(row.wiki_update_help, temp);
16163 str << " -wiki_update_help:";
16164 strptr_PrintBash(temp,str);
16165 }
16166 ind_beg(atf_wcli_wiki_update_fields_curs,value,row) {
16167 ch_RemoveAll(temp);
16168 cstring_Print(value, temp);
16169 str << " -wiki_update_fields:";
16170 strptr_PrintBash(temp,str);
16171 }ind_end;
16172 if (!(row.wiki_clean_start == false)) {
16173 ch_RemoveAll(temp);
16174 bool_Print(row.wiki_clean_start, temp);
16175 str << " -wiki_clean_start:";
16176 strptr_PrintBash(temp,str);
16177 }
16178 if (!(row.authdir_dflt == false)) {
16179 ch_RemoveAll(temp);
16180 bool_Print(row.authdir_dflt, temp);
16181 str << " -authdir_dflt:";
16182 strptr_PrintBash(temp,str);
16183 }
16184 if (!(row.dry_run == false)) {
16185 ch_RemoveAll(temp);
16186 bool_Print(row.dry_run, temp);
16187 str << " -dry_run:";
16188 strptr_PrintBash(temp,str);
16189 }
16190 if (!(row.wikisite == "Openacr")) {
16191 ch_RemoveAll(temp);
16192 Smallstr50_Print(row.wikisite, temp);
16193 str << " -wikisite:";
16194 strptr_PrintBash(temp,str);
16195 }
16196}
16197
16198// --- command.atf_wcli..GetAnon
16199algo::strptr command::atf_wcli_GetAnon(command::atf_wcli &parent, i32 idx) {
16200 (void)parent;//only to avoid -Wunused-parameter
16201 switch(idx) {
16202 default: return strptr("wiki_update_fields", 18);
16203 }
16204}
16205
16206// --- command.atf_wcli..NArgs
16207// Used with command lines
16208// Return # of command-line arguments that must follow this argument
16209// If FIELD is invalid, return -1
16210i32 command::atf_wcli_NArgs(command::FieldId field, algo::strptr& out_dflt, bool* out_anon) {
16211 i32 retval = 1;
16212 switch (field) {
16213 case command_FieldId_capture: { // $comment
16214 *out_anon = false;
16215 retval=0;
16216 out_dflt="Y";
16217 } break;
16218 case command_FieldId_wtblacttst: { // bool: no argument required but value may be specified as capture:Y
16219 *out_anon = false;
16220 } break;
16221 case command_FieldId_in: { // bool: no argument required but value may be specified as capture:Y
16222 *out_anon = false;
16223 } break;
16224 case command_FieldId_wiki_envnode: { // bool: no argument required but value may be specified as capture:Y
16225 *out_anon = false;
16226 } break;
16227 case command_FieldId_wiki_kill: { // bool: no argument required but value may be specified as capture:Y
16228 *out_anon = false;
16229 retval=0;
16230 out_dflt="Y";
16231 } break;
16232 case command_FieldId_wiki_start: { // bool: no argument required but value may be specified as wiki_kill:Y
16233 *out_anon = false;
16234 retval=0;
16235 out_dflt="Y";
16236 } break;
16237 case command_FieldId_wiki_update: { // bool: no argument required but value may be specified as wiki_start:Y
16238 *out_anon = false;
16239 retval=0;
16240 out_dflt="Y";
16241 } break;
16242 case command_FieldId_wiki_update_help: { // bool: no argument required but value may be specified as wiki_update:Y
16243 *out_anon = false;
16244 retval=0;
16245 out_dflt="Y";
16246 } break;
16247 case command_FieldId_wiki_update_fields: { // bool: no argument required but value may be specified as wiki_update_help:Y
16248 *out_anon = true;
16249 } break;
16250 case command_FieldId_wiki_clean_start: { // bool: no argument required but value may be specified as wiki_update_help:Y
16251 *out_anon = false;
16252 retval=0;
16253 out_dflt="Y";
16254 } break;
16255 case command_FieldId_authdir_dflt: { // bool: no argument required but value may be specified as wiki_clean_start:Y
16256 *out_anon = false;
16257 retval=0;
16258 out_dflt="Y";
16259 } break;
16260 case command_FieldId_dry_run: { // bool: no argument required but value may be specified as authdir_dflt:Y
16261 *out_anon = false;
16262 retval=0;
16263 out_dflt="Y";
16264 } break;
16265 case command_FieldId_wikisite: { // bool: no argument required but value may be specified as dry_run:Y
16266 *out_anon = false;
16267 } break;
16268 default:
16269 retval=-1; // unrecognized
16270 }
16271 return retval;
16272}
16273
16274// --- command.atf_wcli_proc.atf_wcli.Start
16275// Start subprocess
16276// If subprocess already running, do nothing. Otherwise, start it
16277int command::atf_wcli_Start(command::atf_wcli_proc& parent) {
16278 int retval = 0;
16279 if (parent.pid == 0) {
16280 verblog(atf_wcli_ToCmdline(parent)); // maybe print command
16281#ifdef WIN32
16282 algo_lib::ResolveExecFname(parent.path);
16283 tempstr cmdline(atf_wcli_ToCmdline(parent));
16284 parent.pid = dospawn(Zeroterm(parent.path),Zeroterm(cmdline),parent.timeout,parent.fstdin,parent.fstdout,parent.fstderr);
16285#else
16286 parent.pid = fork();
16287 if (parent.pid == 0) { // child
16288 algo_lib::DieWithParent();
16289 if (parent.timeout > 0) {
16290 alarm(parent.timeout);
16291 }
16292 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstdin , 0);
16293 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstdout, 1);
16294 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstderr, 2);
16295 if (retval==0) retval= atf_wcli_Execv(parent);
16296 if (retval != 0) { // if start fails, print error
16297 int err=errno;
16298 prerr("command.atf_wcli_execv"
16299 <<Keyval("errno",err)
16300 <<Keyval("errstr",strerror(err))
16301 <<Keyval("comment","Execv failed"));
16302 }
16303 _exit(127); // if failed to start, exit anyway
16304 } else if (parent.pid == -1) {
16305 retval = errno; // failed to fork
16306 }
16307#endif
16308 }
16309 parent.status = parent.pid > 0 ? 0 : -1; // if didn't start, set error status
16310 return retval;
16311}
16312
16313// --- command.atf_wcli_proc.atf_wcli.StartRead
16314// Start subprocess & Read output
16315algo::Fildes command::atf_wcli_StartRead(command::atf_wcli_proc& parent, algo_lib::FFildes &read) {
16316 int pipefd[2];
16317 int rc=pipe(pipefd);
16318 (void)rc;
16319 read.fd.value = pipefd[0];
16320 parent.fstdout << ">&" << pipefd[1];
16321 atf_wcli_Start(parent);
16322 (void)close(pipefd[1]);
16323 return read.fd;
16324}
16325
16326// --- command.atf_wcli_proc.atf_wcli.Kill
16327// Kill subprocess and wait
16328void command::atf_wcli_Kill(command::atf_wcli_proc& parent) {
16329 if (parent.pid != 0) {
16330 kill(parent.pid,9);
16331 atf_wcli_Wait(parent);
16332 }
16333}
16334
16335// --- command.atf_wcli_proc.atf_wcli.Wait
16336// Wait for subprocess to return
16337void command::atf_wcli_Wait(command::atf_wcli_proc& parent) {
16338 if (parent.pid > 0) {
16339 int wait_flags = 0;
16340 int wait_status = 0;
16341 int rc = -1;
16342 do {
16343 // really wait for subprocess to exit
16344 rc = waitpid(parent.pid,&wait_status,wait_flags);
16345 } while (rc==-1 && errno==EINTR);
16346 if (rc == parent.pid) {
16347 parent.status = wait_status;
16348 parent.pid = 0;
16349 }
16350 }
16351}
16352
16353// --- command.atf_wcli_proc.atf_wcli.Exec
16354// Start + Wait
16355// Execute subprocess and return exit code
16356int command::atf_wcli_Exec(command::atf_wcli_proc& parent) {
16357 atf_wcli_Start(parent);
16358 atf_wcli_Wait(parent);
16359 return parent.status;
16360}
16361
16362// --- command.atf_wcli_proc.atf_wcli.ExecX
16363// Start + Wait, throw exception on error
16364// Execute subprocess; throw human-readable exception on error
16365void command::atf_wcli_ExecX(command::atf_wcli_proc& parent) {
16366 int rc = atf_wcli_Exec(parent);
16367 vrfy(rc==0, tempstr() << "algo_lib.exec" << Keyval("cmd",atf_wcli_ToCmdline(parent))
16368 << Keyval("comment",algo::DescribeWaitStatus(parent.status)));
16369}
16370
16371// --- command.atf_wcli_proc.atf_wcli.Execv
16372// Call execv()
16373// Call execv with specified parameters
16374int command::atf_wcli_Execv(command::atf_wcli_proc& parent) {
16375 int ret = 0;
16376 algo::StringAry args;
16377 atf_wcli_ToArgv(parent, args);
16378 char **argv = (char**)alloca((ary_N(args)+1)*sizeof(*argv));
16379 ind_beg(algo::StringAry_ary_curs,arg,args) {
16380 argv[ind_curs(arg).index] = Zeroterm(arg);
16381 }ind_end;
16382 argv[ary_N(args)] = NULL;
16383 // if parent.path is relative, search for it in PATH
16384 algo_lib::ResolveExecFname(parent.path);
16385 ret = execv(Zeroterm(parent.path),argv);
16386 return ret;
16387}
16388
16389// --- command.atf_wcli_proc.atf_wcli.ToCmdline
16390algo::tempstr command::atf_wcli_ToCmdline(command::atf_wcli_proc& parent) {
16391 algo::tempstr retval;
16392 retval << parent.path << " ";
16393 command::atf_wcli_PrintArgv(parent.cmd,retval);
16394 if (ch_N(parent.fstdin)) {
16395 retval << " " << parent.fstdin;
16396 }
16397 if (ch_N(parent.fstdout)) {
16398 retval << " " << parent.fstdout;
16399 }
16400 if (ch_N(parent.fstderr)) {
16401 retval << " 2" << parent.fstderr;
16402 }
16403 return retval;
16404}
16405
16406// --- command.atf_wcli_proc.atf_wcli.ToArgv
16407// Form array from the command line
16408void command::atf_wcli_ToArgv(command::atf_wcli_proc& parent, algo::StringAry& args) {
16409 ary_RemoveAll(args);
16410 ary_Alloc(args) << parent.path;
16411
16412 if (parent.cmd.capture != false) {
16413 cstring *arg = &ary_Alloc(args);
16414 *arg << "-capture:";
16415 bool_Print(parent.cmd.capture, *arg);
16416 }
16417
16418 if (parent.cmd.wtblacttst.expr != "") {
16419 cstring *arg = &ary_Alloc(args);
16420 *arg << "-wtblacttst:";
16421 command::wtblacttst_Print(parent.cmd, *arg);
16422 }
16423
16424 if (parent.cmd.in != "data") {
16425 cstring *arg = &ary_Alloc(args);
16426 *arg << "-in:";
16427 cstring_Print(parent.cmd.in, *arg);
16428 }
16429
16430 if (parent.cmd.wiki_envnode != "dev.wiki-qa1-nyc0") {
16431 cstring *arg = &ary_Alloc(args);
16432 *arg << "-wiki_envnode:";
16433 Smallstr50_Print(parent.cmd.wiki_envnode, *arg);
16434 }
16435
16436 if (parent.cmd.wiki_kill != false) {
16437 cstring *arg = &ary_Alloc(args);
16438 *arg << "-wiki_kill:";
16439 bool_Print(parent.cmd.wiki_kill, *arg);
16440 }
16441
16442 if (parent.cmd.wiki_start != false) {
16443 cstring *arg = &ary_Alloc(args);
16444 *arg << "-wiki_start:";
16445 bool_Print(parent.cmd.wiki_start, *arg);
16446 }
16447
16448 if (parent.cmd.wiki_update != false) {
16449 cstring *arg = &ary_Alloc(args);
16450 *arg << "-wiki_update:";
16451 bool_Print(parent.cmd.wiki_update, *arg);
16452 }
16453
16454 if (parent.cmd.wiki_update_help != false) {
16455 cstring *arg = &ary_Alloc(args);
16456 *arg << "-wiki_update_help:";
16457 bool_Print(parent.cmd.wiki_update_help, *arg);
16458 }
16459 ind_beg(command::atf_wcli_wiki_update_fields_curs,value,parent.cmd) {
16460 cstring *arg = &ary_Alloc(args);
16461 *arg << "-wiki_update_fields:";
16462 cstring_Print(value, *arg);
16463 }ind_end;
16464
16465 if (parent.cmd.wiki_clean_start != false) {
16466 cstring *arg = &ary_Alloc(args);
16467 *arg << "-wiki_clean_start:";
16468 bool_Print(parent.cmd.wiki_clean_start, *arg);
16469 }
16470
16471 if (parent.cmd.authdir_dflt != false) {
16472 cstring *arg = &ary_Alloc(args);
16473 *arg << "-authdir_dflt:";
16474 bool_Print(parent.cmd.authdir_dflt, *arg);
16475 }
16476
16477 if (parent.cmd.dry_run != false) {
16478 cstring *arg = &ary_Alloc(args);
16479 *arg << "-dry_run:";
16480 bool_Print(parent.cmd.dry_run, *arg);
16481 }
16482
16483 if (parent.cmd.wikisite != "Openacr") {
16484 cstring *arg = &ary_Alloc(args);
16485 *arg << "-wikisite:";
16486 Smallstr50_Print(parent.cmd.wikisite, *arg);
16487 }
16488 for (int i=1; i < algo_lib::_db.cmdline.verbose; ++i) {
16489 ary_Alloc(args) << "-verbose";
16490 }
16491}
16492
16493// --- command.atf_wcli_proc..Uninit
16494void command::atf_wcli_proc_Uninit(command::atf_wcli_proc& parent) {
16495 command::atf_wcli_proc &row = parent; (void)row;
16496
16497 // command.atf_wcli_proc.atf_wcli.Uninit (Exec) //
16498 atf_wcli_Kill(parent); // kill child, ensure forward progress
16499}
16500
16501// --- command.atf_ws..ReadFieldMaybe
16502bool command::atf_ws_ReadFieldMaybe(command::atf_ws& parent, algo::strptr field, algo::strptr strval) {
16503 bool retval = true;
16504 command::FieldId field_id;
16505 (void)value_SetStrptrMaybe(field_id,field);
16506 switch(field_id) {
16507 case command_FieldId_in: {
16508 retval = algo::cstring_ReadStrptrMaybe(parent.in, strval);
16509 break;
16510 }
16511 case command_FieldId_randomize_ports: {
16512 retval = bool_ReadStrptrMaybe(parent.randomize_ports, strval);
16513 break;
16514 }
16515 default: break;
16516 }
16517 if (!retval) {
16518 algo_lib::AppendErrtext("attr",field);
16519 }
16520 return retval;
16521}
16522
16523// --- command.atf_ws..ReadTupleMaybe
16524// Read fields of command::atf_ws from attributes of ascii tuple TUPLE
16525bool command::atf_ws_ReadTupleMaybe(command::atf_ws &parent, algo::Tuple &tuple) {
16526 bool retval = true;
16527 ind_beg(algo::Tuple_attrs_curs,attr,tuple) {
16528 retval = atf_ws_ReadFieldMaybe(parent, attr.name, attr.value);
16529 if (!retval) {
16530 break;
16531 }
16532 }ind_end;
16533 return retval;
16534}
16535
16536// --- command.atf_ws..ToCmdline
16537// Convenience function that returns a full command line
16538// Assume command is in a directory called bin
16539tempstr command::atf_ws_ToCmdline(command::atf_ws& row) {
16540 tempstr ret;
16541 ret << "bin/atf_ws ";
16542 atf_ws_PrintArgv(row, ret);
16543 // inherit less intense verbose, debug options
16544 for (int i = 1; i < algo_lib::_db.cmdline.verbose; i++) {
16545 ret << " -verbose";
16546 }
16547 for (int i = 1; i < algo_lib::_db.cmdline.debug; i++) {
16548 ret << " -debug";
16549 }
16550 return ret;
16551}
16552
16553// --- command.atf_ws..PrintArgv
16554// print string representation of ROW to string STR
16555// cfmt:command.atf_ws.Argv printfmt:Tuple
16556void command::atf_ws_PrintArgv(command::atf_ws& row, algo::cstring& str) {
16557 algo::tempstr temp;
16558 (void)temp;
16559 (void)str;
16560 if (!(row.in == "data")) {
16561 ch_RemoveAll(temp);
16562 cstring_Print(row.in, temp);
16563 str << " -in:";
16564 strptr_PrintBash(temp,str);
16565 }
16566 if (!(row.randomize_ports == true)) {
16567 ch_RemoveAll(temp);
16568 bool_Print(row.randomize_ports, temp);
16569 str << " -randomize_ports:";
16570 strptr_PrintBash(temp,str);
16571 }
16572}
16573
16574// --- command.atf_ws..NArgs
16575// Used with command lines
16576// Return # of command-line arguments that must follow this argument
16577// If FIELD is invalid, return -1
16578i32 command::atf_ws_NArgs(command::FieldId field, algo::strptr& out_dflt, bool* out_anon) {
16579 i32 retval = 1;
16580 switch (field) {
16581 case command_FieldId_in: { // $comment
16582 *out_anon = false;
16583 } break;
16584 case command_FieldId_randomize_ports: { // $comment
16585 *out_anon = false;
16586 retval=0;
16587 out_dflt="Y";
16588 } break;
16589 default:
16590 retval=-1; // unrecognized
16591 }
16592 return retval;
16593}
16594
16595// --- command.atf_ws_proc.atf_ws.Start
16596// Start subprocess
16597// If subprocess already running, do nothing. Otherwise, start it
16598int command::atf_ws_Start(command::atf_ws_proc& parent) {
16599 int retval = 0;
16600 if (parent.pid == 0) {
16601 verblog(atf_ws_ToCmdline(parent)); // maybe print command
16602#ifdef WIN32
16603 algo_lib::ResolveExecFname(parent.path);
16604 tempstr cmdline(atf_ws_ToCmdline(parent));
16605 parent.pid = dospawn(Zeroterm(parent.path),Zeroterm(cmdline),parent.timeout,parent.fstdin,parent.fstdout,parent.fstderr);
16606#else
16607 parent.pid = fork();
16608 if (parent.pid == 0) { // child
16609 algo_lib::DieWithParent();
16610 if (parent.timeout > 0) {
16611 alarm(parent.timeout);
16612 }
16613 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstdin , 0);
16614 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstdout, 1);
16615 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstderr, 2);
16616 if (retval==0) retval= atf_ws_Execv(parent);
16617 if (retval != 0) { // if start fails, print error
16618 int err=errno;
16619 prerr("command.atf_ws_execv"
16620 <<Keyval("errno",err)
16621 <<Keyval("errstr",strerror(err))
16622 <<Keyval("comment","Execv failed"));
16623 }
16624 _exit(127); // if failed to start, exit anyway
16625 } else if (parent.pid == -1) {
16626 retval = errno; // failed to fork
16627 }
16628#endif
16629 }
16630 parent.status = parent.pid > 0 ? 0 : -1; // if didn't start, set error status
16631 return retval;
16632}
16633
16634// --- command.atf_ws_proc.atf_ws.StartRead
16635// Start subprocess & Read output
16636algo::Fildes command::atf_ws_StartRead(command::atf_ws_proc& parent, algo_lib::FFildes &read) {
16637 int pipefd[2];
16638 int rc=pipe(pipefd);
16639 (void)rc;
16640 read.fd.value = pipefd[0];
16641 parent.fstdout << ">&" << pipefd[1];
16642 atf_ws_Start(parent);
16643 (void)close(pipefd[1]);
16644 return read.fd;
16645}
16646
16647// --- command.atf_ws_proc.atf_ws.Kill
16648// Kill subprocess and wait
16649void command::atf_ws_Kill(command::atf_ws_proc& parent) {
16650 if (parent.pid != 0) {
16651 kill(parent.pid,9);
16652 atf_ws_Wait(parent);
16653 }
16654}
16655
16656// --- command.atf_ws_proc.atf_ws.Wait
16657// Wait for subprocess to return
16658void command::atf_ws_Wait(command::atf_ws_proc& parent) {
16659 if (parent.pid > 0) {
16660 int wait_flags = 0;
16661 int wait_status = 0;
16662 int rc = -1;
16663 do {
16664 // really wait for subprocess to exit
16665 rc = waitpid(parent.pid,&wait_status,wait_flags);
16666 } while (rc==-1 && errno==EINTR);
16667 if (rc == parent.pid) {
16668 parent.status = wait_status;
16669 parent.pid = 0;
16670 }
16671 }
16672}
16673
16674// --- command.atf_ws_proc.atf_ws.Exec
16675// Start + Wait
16676// Execute subprocess and return exit code
16677int command::atf_ws_Exec(command::atf_ws_proc& parent) {
16678 atf_ws_Start(parent);
16679 atf_ws_Wait(parent);
16680 return parent.status;
16681}
16682
16683// --- command.atf_ws_proc.atf_ws.ExecX
16684// Start + Wait, throw exception on error
16685// Execute subprocess; throw human-readable exception on error
16686void command::atf_ws_ExecX(command::atf_ws_proc& parent) {
16687 int rc = atf_ws_Exec(parent);
16688 vrfy(rc==0, tempstr() << "algo_lib.exec" << Keyval("cmd",atf_ws_ToCmdline(parent))
16689 << Keyval("comment",algo::DescribeWaitStatus(parent.status)));
16690}
16691
16692// --- command.atf_ws_proc.atf_ws.Execv
16693// Call execv()
16694// Call execv with specified parameters
16695int command::atf_ws_Execv(command::atf_ws_proc& parent) {
16696 int ret = 0;
16697 algo::StringAry args;
16698 atf_ws_ToArgv(parent, args);
16699 char **argv = (char**)alloca((ary_N(args)+1)*sizeof(*argv));
16700 ind_beg(algo::StringAry_ary_curs,arg,args) {
16701 argv[ind_curs(arg).index] = Zeroterm(arg);
16702 }ind_end;
16703 argv[ary_N(args)] = NULL;
16704 // if parent.path is relative, search for it in PATH
16705 algo_lib::ResolveExecFname(parent.path);
16706 ret = execv(Zeroterm(parent.path),argv);
16707 return ret;
16708}
16709
16710// --- command.atf_ws_proc.atf_ws.ToCmdline
16711algo::tempstr command::atf_ws_ToCmdline(command::atf_ws_proc& parent) {
16712 algo::tempstr retval;
16713 retval << parent.path << " ";
16714 command::atf_ws_PrintArgv(parent.cmd,retval);
16715 if (ch_N(parent.fstdin)) {
16716 retval << " " << parent.fstdin;
16717 }
16718 if (ch_N(parent.fstdout)) {
16719 retval << " " << parent.fstdout;
16720 }
16721 if (ch_N(parent.fstderr)) {
16722 retval << " 2" << parent.fstderr;
16723 }
16724 return retval;
16725}
16726
16727// --- command.atf_ws_proc.atf_ws.ToArgv
16728// Form array from the command line
16729void command::atf_ws_ToArgv(command::atf_ws_proc& parent, algo::StringAry& args) {
16730 ary_RemoveAll(args);
16731 ary_Alloc(args) << parent.path;
16732
16733 if (parent.cmd.in != "data") {
16734 cstring *arg = &ary_Alloc(args);
16735 *arg << "-in:";
16736 cstring_Print(parent.cmd.in, *arg);
16737 }
16738
16739 if (parent.cmd.randomize_ports != true) {
16740 cstring *arg = &ary_Alloc(args);
16741 *arg << "-randomize_ports:";
16742 bool_Print(parent.cmd.randomize_ports, *arg);
16743 }
16744 for (int i=1; i < algo_lib::_db.cmdline.verbose; ++i) {
16745 ary_Alloc(args) << "-verbose";
16746 }
16747}
16748
16749// --- command.atf_ws_proc..Uninit
16750void command::atf_ws_proc_Uninit(command::atf_ws_proc& parent) {
16751 command::atf_ws_proc &row = parent; (void)row;
16752
16753 // command.atf_ws_proc.atf_ws.Uninit (Exec) //
16754 atf_ws_Kill(parent); // kill child, ensure forward progress
16755}
16756
16757// --- command.bash..PrintArgv
16758// print string representation of ROW to string STR
16759// cfmt:command.bash.ArgvGnu printfmt:Auto
16760void command::bash_PrintArgv(command::bash& row, algo::cstring& str) {
16761 algo::tempstr temp;
16762 (void)temp;
16763 (void)str;
16764 if (!(row.c == "")) {
16765 ch_RemoveAll(temp);
16766 cstring_Print(row.c, temp);
16767 str << " -c ";
16768 strptr_PrintBash(temp,str);
16769 }
16770}
16771
16772// --- command.bash2html..ReadFieldMaybe
16773bool command::bash2html_ReadFieldMaybe(command::bash2html& parent, algo::strptr field, algo::strptr strval) {
16774 bool retval = true;
16775 command::FieldId field_id;
16776 (void)value_SetStrptrMaybe(field_id,field);
16777 switch(field_id) {
16778 case command_FieldId_in: {
16779 retval = algo::cstring_ReadStrptrMaybe(parent.in, strval);
16780 break;
16781 }
16782 case command_FieldId_test: {
16783 retval = bool_ReadStrptrMaybe(parent.test, strval);
16784 break;
16785 }
16786 default: break;
16787 }
16788 if (!retval) {
16789 algo_lib::AppendErrtext("attr",field);
16790 }
16791 return retval;
16792}
16793
16794// --- command.bash2html..ReadTupleMaybe
16795// Read fields of command::bash2html from attributes of ascii tuple TUPLE
16796bool command::bash2html_ReadTupleMaybe(command::bash2html &parent, algo::Tuple &tuple) {
16797 bool retval = true;
16798 ind_beg(algo::Tuple_attrs_curs,attr,tuple) {
16799 retval = bash2html_ReadFieldMaybe(parent, attr.name, attr.value);
16800 if (!retval) {
16801 break;
16802 }
16803 }ind_end;
16804 return retval;
16805}
16806
16807// --- command.bash2html..ToCmdline
16808// Convenience function that returns a full command line
16809// Assume command is in a directory called bin
16810tempstr command::bash2html_ToCmdline(command::bash2html& row) {
16811 tempstr ret;
16812 ret << "bin/bash2html ";
16813 bash2html_PrintArgv(row, ret);
16814 // inherit less intense verbose, debug options
16815 for (int i = 1; i < algo_lib::_db.cmdline.verbose; i++) {
16816 ret << " -verbose";
16817 }
16818 for (int i = 1; i < algo_lib::_db.cmdline.debug; i++) {
16819 ret << " -debug";
16820 }
16821 return ret;
16822}
16823
16824// --- command.bash2html..PrintArgv
16825// print string representation of ROW to string STR
16826// cfmt:command.bash2html.Argv printfmt:Tuple
16827void command::bash2html_PrintArgv(command::bash2html& row, algo::cstring& str) {
16828 algo::tempstr temp;
16829 (void)temp;
16830 (void)str;
16831 if (!(row.in == "data")) {
16832 ch_RemoveAll(temp);
16833 cstring_Print(row.in, temp);
16834 str << " -in:";
16835 strptr_PrintBash(temp,str);
16836 }
16837 if (!(row.test == false)) {
16838 ch_RemoveAll(temp);
16839 bool_Print(row.test, temp);
16840 str << " -test:";
16841 strptr_PrintBash(temp,str);
16842 }
16843}
16844
16845// --- command.bash2html..NArgs
16846// Used with command lines
16847// Return # of command-line arguments that must follow this argument
16848// If FIELD is invalid, return -1
16849i32 command::bash2html_NArgs(command::FieldId field, algo::strptr& out_dflt, bool* out_anon) {
16850 i32 retval = 1;
16851 switch (field) {
16852 case command_FieldId_in: { // $comment
16853 *out_anon = false;
16854 } break;
16855 case command_FieldId_test: { // $comment
16856 *out_anon = false;
16857 retval=0;
16858 out_dflt="Y";
16859 } break;
16860 default:
16861 retval=-1; // unrecognized
16862 }
16863 return retval;
16864}
16865
16866// --- command.bash2html_proc.bash2html.Start
16867// Start subprocess
16868// If subprocess already running, do nothing. Otherwise, start it
16869int command::bash2html_Start(command::bash2html_proc& parent) {
16870 int retval = 0;
16871 if (parent.pid == 0) {
16872 verblog(bash2html_ToCmdline(parent)); // maybe print command
16873#ifdef WIN32
16874 algo_lib::ResolveExecFname(parent.path);
16875 tempstr cmdline(bash2html_ToCmdline(parent));
16876 parent.pid = dospawn(Zeroterm(parent.path),Zeroterm(cmdline),parent.timeout,parent.fstdin,parent.fstdout,parent.fstderr);
16877#else
16878 parent.pid = fork();
16879 if (parent.pid == 0) { // child
16880 algo_lib::DieWithParent();
16881 if (parent.timeout > 0) {
16882 alarm(parent.timeout);
16883 }
16884 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstdin , 0);
16885 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstdout, 1);
16886 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstderr, 2);
16887 if (retval==0) retval= bash2html_Execv(parent);
16888 if (retval != 0) { // if start fails, print error
16889 int err=errno;
16890 prerr("command.bash2html_execv"
16891 <<Keyval("errno",err)
16892 <<Keyval("errstr",strerror(err))
16893 <<Keyval("comment","Execv failed"));
16894 }
16895 _exit(127); // if failed to start, exit anyway
16896 } else if (parent.pid == -1) {
16897 retval = errno; // failed to fork
16898 }
16899#endif
16900 }
16901 parent.status = parent.pid > 0 ? 0 : -1; // if didn't start, set error status
16902 return retval;
16903}
16904
16905// --- command.bash2html_proc.bash2html.StartRead
16906// Start subprocess & Read output
16907algo::Fildes command::bash2html_StartRead(command::bash2html_proc& parent, algo_lib::FFildes &read) {
16908 int pipefd[2];
16909 int rc=pipe(pipefd);
16910 (void)rc;
16911 read.fd.value = pipefd[0];
16912 parent.fstdout << ">&" << pipefd[1];
16913 bash2html_Start(parent);
16914 (void)close(pipefd[1]);
16915 return read.fd;
16916}
16917
16918// --- command.bash2html_proc.bash2html.Kill
16919// Kill subprocess and wait
16920void command::bash2html_Kill(command::bash2html_proc& parent) {
16921 if (parent.pid != 0) {
16922 kill(parent.pid,9);
16923 bash2html_Wait(parent);
16924 }
16925}
16926
16927// --- command.bash2html_proc.bash2html.Wait
16928// Wait for subprocess to return
16929void command::bash2html_Wait(command::bash2html_proc& parent) {
16930 if (parent.pid > 0) {
16931 int wait_flags = 0;
16932 int wait_status = 0;
16933 int rc = -1;
16934 do {
16935 // really wait for subprocess to exit
16936 rc = waitpid(parent.pid,&wait_status,wait_flags);
16937 } while (rc==-1 && errno==EINTR);
16938 if (rc == parent.pid) {
16939 parent.status = wait_status;
16940 parent.pid = 0;
16941 }
16942 }
16943}
16944
16945// --- command.bash2html_proc.bash2html.Exec
16946// Start + Wait
16947// Execute subprocess and return exit code
16948int command::bash2html_Exec(command::bash2html_proc& parent) {
16949 bash2html_Start(parent);
16950 bash2html_Wait(parent);
16951 return parent.status;
16952}
16953
16954// --- command.bash2html_proc.bash2html.ExecX
16955// Start + Wait, throw exception on error
16956// Execute subprocess; throw human-readable exception on error
16957void command::bash2html_ExecX(command::bash2html_proc& parent) {
16958 int rc = bash2html_Exec(parent);
16959 vrfy(rc==0, tempstr() << "algo_lib.exec" << Keyval("cmd",bash2html_ToCmdline(parent))
16960 << Keyval("comment",algo::DescribeWaitStatus(parent.status)));
16961}
16962
16963// --- command.bash2html_proc.bash2html.Execv
16964// Call execv()
16965// Call execv with specified parameters
16966int command::bash2html_Execv(command::bash2html_proc& parent) {
16967 int ret = 0;
16968 algo::StringAry args;
16969 bash2html_ToArgv(parent, args);
16970 char **argv = (char**)alloca((ary_N(args)+1)*sizeof(*argv));
16971 ind_beg(algo::StringAry_ary_curs,arg,args) {
16972 argv[ind_curs(arg).index] = Zeroterm(arg);
16973 }ind_end;
16974 argv[ary_N(args)] = NULL;
16975 // if parent.path is relative, search for it in PATH
16976 algo_lib::ResolveExecFname(parent.path);
16977 ret = execv(Zeroterm(parent.path),argv);
16978 return ret;
16979}
16980
16981// --- command.bash2html_proc.bash2html.ToCmdline
16982algo::tempstr command::bash2html_ToCmdline(command::bash2html_proc& parent) {
16983 algo::tempstr retval;
16984 retval << parent.path << " ";
16985 command::bash2html_PrintArgv(parent.cmd,retval);
16986 if (ch_N(parent.fstdin)) {
16987 retval << " " << parent.fstdin;
16988 }
16989 if (ch_N(parent.fstdout)) {
16990 retval << " " << parent.fstdout;
16991 }
16992 if (ch_N(parent.fstderr)) {
16993 retval << " 2" << parent.fstderr;
16994 }
16995 return retval;
16996}
16997
16998// --- command.bash2html_proc.bash2html.ToArgv
16999// Form array from the command line
17000void command::bash2html_ToArgv(command::bash2html_proc& parent, algo::StringAry& args) {
17001 ary_RemoveAll(args);
17002 ary_Alloc(args) << parent.path;
17003
17004 if (parent.cmd.in != "data") {
17005 cstring *arg = &ary_Alloc(args);
17006 *arg << "-in:";
17007 cstring_Print(parent.cmd.in, *arg);
17008 }
17009
17010 if (parent.cmd.test != false) {
17011 cstring *arg = &ary_Alloc(args);
17012 *arg << "-test:";
17013 bool_Print(parent.cmd.test, *arg);
17014 }
17015 for (int i=1; i < algo_lib::_db.cmdline.verbose; ++i) {
17016 ary_Alloc(args) << "-verbose";
17017 }
17018}
17019
17020// --- command.bash2html_proc..Uninit
17021void command::bash2html_proc_Uninit(command::bash2html_proc& parent) {
17022 command::bash2html_proc &row = parent; (void)row;
17023
17024 // command.bash2html_proc.bash2html.Uninit (Exec) //
17025 bash2html_Kill(parent); // kill child, ensure forward progress
17026}
17027
17028// --- command.bash_proc.bash.Start
17029// Start subprocess
17030// If subprocess already running, do nothing. Otherwise, start it
17031int command::bash_Start(command::bash_proc& parent) {
17032 int retval = 0;
17033 if (parent.pid == 0) {
17034 verblog(bash_ToCmdline(parent)); // maybe print command
17035#ifdef WIN32
17036 algo_lib::ResolveExecFname(parent.path);
17037 tempstr cmdline(bash_ToCmdline(parent));
17038 parent.pid = dospawn(Zeroterm(parent.path),Zeroterm(cmdline),parent.timeout,parent.fstdin,parent.fstdout,parent.fstderr);
17039#else
17040 parent.pid = fork();
17041 if (parent.pid == 0) { // child
17042 algo_lib::DieWithParent();
17043 if (parent.timeout > 0) {
17044 alarm(parent.timeout);
17045 }
17046 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstdin , 0);
17047 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstdout, 1);
17048 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstderr, 2);
17049 if (retval==0) retval= bash_Execv(parent);
17050 if (retval != 0) { // if start fails, print error
17051 int err=errno;
17052 prerr("command.bash_execv"
17053 <<Keyval("errno",err)
17054 <<Keyval("errstr",strerror(err))
17055 <<Keyval("comment","Execv failed"));
17056 }
17057 _exit(127); // if failed to start, exit anyway
17058 } else if (parent.pid == -1) {
17059 retval = errno; // failed to fork
17060 }
17061#endif
17062 }
17063 parent.status = parent.pid > 0 ? 0 : -1; // if didn't start, set error status
17064 return retval;
17065}
17066
17067// --- command.bash_proc.bash.StartRead
17068// Start subprocess & Read output
17069algo::Fildes command::bash_StartRead(command::bash_proc& parent, algo_lib::FFildes &read) {
17070 int pipefd[2];
17071 int rc=pipe(pipefd);
17072 (void)rc;
17073 read.fd.value = pipefd[0];
17074 parent.fstdout << ">&" << pipefd[1];
17075 bash_Start(parent);
17076 (void)close(pipefd[1]);
17077 return read.fd;
17078}
17079
17080// --- command.bash_proc.bash.Kill
17081// Kill subprocess and wait
17082void command::bash_Kill(command::bash_proc& parent) {
17083 if (parent.pid != 0) {
17084 kill(parent.pid,9);
17085 bash_Wait(parent);
17086 }
17087}
17088
17089// --- command.bash_proc.bash.Wait
17090// Wait for subprocess to return
17091void command::bash_Wait(command::bash_proc& parent) {
17092 if (parent.pid > 0) {
17093 int wait_flags = 0;
17094 int wait_status = 0;
17095 int rc = -1;
17096 do {
17097 // really wait for subprocess to exit
17098 rc = waitpid(parent.pid,&wait_status,wait_flags);
17099 } while (rc==-1 && errno==EINTR);
17100 if (rc == parent.pid) {
17101 parent.status = wait_status;
17102 parent.pid = 0;
17103 }
17104 }
17105}
17106
17107// --- command.bash_proc.bash.Exec
17108// Start + Wait
17109// Execute subprocess and return exit code
17110int command::bash_Exec(command::bash_proc& parent) {
17111 bash_Start(parent);
17112 bash_Wait(parent);
17113 return parent.status;
17114}
17115
17116// --- command.bash_proc.bash.ExecX
17117// Start + Wait, throw exception on error
17118// Execute subprocess; throw human-readable exception on error
17119void command::bash_ExecX(command::bash_proc& parent) {
17120 int rc = bash_Exec(parent);
17121 vrfy(rc==0, tempstr() << "algo_lib.exec" << Keyval("cmd",bash_ToCmdline(parent))
17122 << Keyval("comment",algo::DescribeWaitStatus(parent.status)));
17123}
17124
17125// --- command.bash_proc.bash.Execv
17126// Call execv()
17127// Call execv with specified parameters
17128int command::bash_Execv(command::bash_proc& parent) {
17129 int ret = 0;
17130 algo::StringAry args;
17131 bash_ToArgv(parent, args);
17132 char **argv = (char**)alloca((ary_N(args)+1)*sizeof(*argv));
17133 ind_beg(algo::StringAry_ary_curs,arg,args) {
17134 argv[ind_curs(arg).index] = Zeroterm(arg);
17135 }ind_end;
17136 argv[ary_N(args)] = NULL;
17137 // if parent.path is relative, search for it in PATH
17138 algo_lib::ResolveExecFname(parent.path);
17139 ret = execv(Zeroterm(parent.path),argv);
17140 return ret;
17141}
17142
17143// --- command.bash_proc.bash.ToCmdline
17144algo::tempstr command::bash_ToCmdline(command::bash_proc& parent) {
17145 algo::tempstr retval;
17146 retval << parent.path << " ";
17147 command::bash_PrintArgv(parent.cmd,retval);
17148 if (ch_N(parent.fstdin)) {
17149 retval << " " << parent.fstdin;
17150 }
17151 if (ch_N(parent.fstdout)) {
17152 retval << " " << parent.fstdout;
17153 }
17154 if (ch_N(parent.fstderr)) {
17155 retval << " 2" << parent.fstderr;
17156 }
17157 return retval;
17158}
17159
17160// --- command.bash_proc.bash.ToArgv
17161// Form array from the command line
17162void command::bash_ToArgv(command::bash_proc& parent, algo::StringAry& args) {
17163 ary_RemoveAll(args);
17164 ary_Alloc(args) << parent.path;
17165
17166 if (parent.cmd.c != "") {
17167 ary_Alloc(args) << "-c";
17168 cstring *arg = &ary_Alloc(args);
17169 cstring_Print(parent.cmd.c, *arg);
17170 }
17171}
17172
17173// --- command.bash_proc..Uninit
17174void command::bash_proc_Uninit(command::bash_proc& parent) {
17175 command::bash_proc &row = parent; (void)row;
17176
17177 // command.bash_proc.bash.Uninit (Exec) //Must be bash to support $'' for string quoting
17178 bash_Kill(parent); // kill child, ensure forward progress
17179}
17180
17181// --- command.dcli.dhost.Print
17182// Print back to string
17183void command::dhost_Print(command::dcli& parent, algo::cstring &out) {
17184 Regx_Print(parent.dhost, out);
17185}
17186
17187// --- command.dcli.dhost.ReadStrptrMaybe
17188// Read Regx from string
17189// Convert string to field. Return success value
17190bool command::dhost_ReadStrptrMaybe(command::dcli& parent, algo::strptr in) {
17191 bool retval = true;
17192 Regx_ReadSql(parent.dhost, in, true);
17193 return retval;
17194}
17195
17196// --- command.dcli.dctr.Print
17197// Print back to string
17198void command::dctr_Print(command::dcli& parent, algo::cstring &out) {
17199 Regx_Print(parent.dctr, out);
17200}
17201
17202// --- command.dcli.dctr.ReadStrptrMaybe
17203// Read Regx from string
17204// Convert string to field. Return success value
17205bool command::dctr_ReadStrptrMaybe(command::dcli& parent, algo::strptr in) {
17206 bool retval = true;
17207 Regx_ReadSql(parent.dctr, in, true);
17208 return retval;
17209}
17210
17211// --- command.dcli.dctrhost.Print
17212// Print back to string
17213void command::dctrhost_Print(command::dcli& parent, algo::cstring &out) {
17214 Regx_Print(parent.dctrhost, out);
17215}
17216
17217// --- command.dcli.dctrhost.ReadStrptrMaybe
17218// Read Regx from string
17219// Convert string to field. Return success value
17220bool command::dctrhost_ReadStrptrMaybe(command::dcli& parent, algo::strptr in) {
17221 bool retval = true;
17222 Regx_ReadSql(parent.dctrhost, in, true);
17223 return retval;
17224}
17225
17226// --- command.dcli..ReadFieldMaybe
17227bool command::dcli_ReadFieldMaybe(command::dcli& parent, algo::strptr field, algo::strptr strval) {
17228 bool retval = true;
17229 command::FieldId field_id;
17230 (void)value_SetStrptrMaybe(field_id,field);
17231 switch(field_id) {
17232 case command_FieldId_in: {
17233 retval = algo::cstring_ReadStrptrMaybe(parent.in, strval);
17234 break;
17235 }
17236 case command_FieldId_cmd: {
17237 retval = algo::cstring_ReadStrptrMaybe(parent.cmd, strval);
17238 break;
17239 }
17240 case command_FieldId_cmd_dctr: {
17241 retval = algo::cstring_ReadStrptrMaybe(parent.cmd_dctr, strval);
17242 break;
17243 }
17244 case command_FieldId_config_ssh: {
17245 retval = bool_ReadStrptrMaybe(parent.config_ssh, strval);
17246 break;
17247 }
17248 case command_FieldId_config_ssh_vpn: {
17249 retval = bool_ReadStrptrMaybe(parent.config_ssh_vpn, strval);
17250 break;
17251 }
17252 case command_FieldId_clean_run: {
17253 retval = bool_ReadStrptrMaybe(parent.clean_run, strval);
17254 break;
17255 }
17256 case command_FieldId_shell: {
17257 retval = bool_ReadStrptrMaybe(parent.shell, strval);
17258 break;
17259 }
17260 case command_FieldId_inspect: {
17261 retval = bool_ReadStrptrMaybe(parent.inspect, strval);
17262 break;
17263 }
17264 case command_FieldId_logs: {
17265 retval = bool_ReadStrptrMaybe(parent.logs, strval);
17266 break;
17267 }
17268 case command_FieldId_generate_build: {
17269 retval = bool_ReadStrptrMaybe(parent.generate_build, strval);
17270 break;
17271 }
17272 case command_FieldId_build: {
17273 retval = bool_ReadStrptrMaybe(parent.build, strval);
17274 break;
17275 }
17276 case command_FieldId_dhost: {
17277 retval = dhost_ReadStrptrMaybe(parent, strval);
17278 break;
17279 }
17280 case command_FieldId_dctr: {
17281 retval = dctr_ReadStrptrMaybe(parent, strval);
17282 break;
17283 }
17284 case command_FieldId_dctrhost: {
17285 retval = dctrhost_ReadStrptrMaybe(parent, strval);
17286 break;
17287 }
17288 case command_FieldId_t: {
17289 retval = bool_ReadStrptrMaybe(parent.t, strval);
17290 break;
17291 }
17292 case command_FieldId_q: {
17293 retval = bool_ReadStrptrMaybe(parent.q, strval);
17294 break;
17295 }
17296 case command_FieldId_dry_run: {
17297 retval = bool_ReadStrptrMaybe(parent.dry_run, strval);
17298 break;
17299 }
17300 default: break;
17301 }
17302 if (!retval) {
17303 algo_lib::AppendErrtext("attr",field);
17304 }
17305 return retval;
17306}
17307
17308// --- command.dcli..ReadTupleMaybe
17309// Read fields of command::dcli from attributes of ascii tuple TUPLE
17310bool command::dcli_ReadTupleMaybe(command::dcli &parent, algo::Tuple &tuple) {
17311 bool retval = true;
17312 int anon_idx = 0;
17313 ind_beg(algo::Tuple_attrs_curs,attr,tuple) {
17314 if (ch_N(attr.name) == 0) {
17315 attr.name = dcli_GetAnon(parent, anon_idx++);
17316 }
17317 retval = dcli_ReadFieldMaybe(parent, attr.name, attr.value);
17318 if (!retval) {
17319 break;
17320 }
17321 }ind_end;
17322 return retval;
17323}
17324
17325// --- command.dcli..Init
17326// Set all fields to initial values.
17327void command::dcli_Init(command::dcli& parent) {
17328 parent.in = algo::strptr("data");
17329 parent.cmd = algo::strptr("");
17330 parent.cmd_dctr = algo::strptr("");
17331 parent.config_ssh = bool(false);
17332 parent.config_ssh_vpn = bool(false);
17333 parent.clean_run = bool(false);
17334 parent.shell = bool(false);
17335 parent.inspect = bool(false);
17336 parent.logs = bool(false);
17337 parent.generate_build = bool(false);
17338 parent.build = bool(false);
17339 Regx_ReadSql(parent.dhost, "", true);
17340 Regx_ReadSql(parent.dctr, "", true);
17341 Regx_ReadSql(parent.dctrhost, "", true);
17342 parent.t = bool(false);
17343 parent.q = bool(false);
17344 parent.dry_run = bool(false);
17345}
17346
17347// --- command.dcli..ToCmdline
17348// Convenience function that returns a full command line
17349// Assume command is in a directory called bin
17350tempstr command::dcli_ToCmdline(command::dcli& row) {
17351 tempstr ret;
17352 ret << "bin/dcli ";
17353 dcli_PrintArgv(row, ret);
17354 // inherit less intense verbose, debug options
17355 for (int i = 1; i < algo_lib::_db.cmdline.verbose; i++) {
17356 ret << " -verbose";
17357 }
17358 for (int i = 1; i < algo_lib::_db.cmdline.debug; i++) {
17359 ret << " -debug";
17360 }
17361 return ret;
17362}
17363
17364// --- command.dcli..PrintArgv
17365// print string representation of ROW to string STR
17366// cfmt:command.dcli.Argv printfmt:Tuple
17367void command::dcli_PrintArgv(command::dcli& row, algo::cstring& str) {
17368 algo::tempstr temp;
17369 (void)temp;
17370 (void)str;
17371 if (!(row.in == "data")) {
17372 ch_RemoveAll(temp);
17373 cstring_Print(row.in, temp);
17374 str << " -in:";
17375 strptr_PrintBash(temp,str);
17376 }
17377 ch_RemoveAll(temp);
17378 cstring_Print(row.cmd, temp);
17379 str << " -cmd:";
17380 strptr_PrintBash(temp,str);
17381 if (!(row.cmd_dctr == "")) {
17382 ch_RemoveAll(temp);
17383 cstring_Print(row.cmd_dctr, temp);
17384 str << " -cmd_dctr:";
17385 strptr_PrintBash(temp,str);
17386 }
17387 if (!(row.config_ssh == false)) {
17388 ch_RemoveAll(temp);
17389 bool_Print(row.config_ssh, temp);
17390 str << " -config_ssh:";
17391 strptr_PrintBash(temp,str);
17392 }
17393 if (!(row.config_ssh_vpn == false)) {
17394 ch_RemoveAll(temp);
17395 bool_Print(row.config_ssh_vpn, temp);
17396 str << " -config_ssh_vpn:";
17397 strptr_PrintBash(temp,str);
17398 }
17399 if (!(row.clean_run == false)) {
17400 ch_RemoveAll(temp);
17401 bool_Print(row.clean_run, temp);
17402 str << " -clean_run:";
17403 strptr_PrintBash(temp,str);
17404 }
17405 if (!(row.shell == false)) {
17406 ch_RemoveAll(temp);
17407 bool_Print(row.shell, temp);
17408 str << " -shell:";
17409 strptr_PrintBash(temp,str);
17410 }
17411 if (!(row.inspect == false)) {
17412 ch_RemoveAll(temp);
17413 bool_Print(row.inspect, temp);
17414 str << " -inspect:";
17415 strptr_PrintBash(temp,str);
17416 }
17417 if (!(row.logs == false)) {
17418 ch_RemoveAll(temp);
17419 bool_Print(row.logs, temp);
17420 str << " -logs:";
17421 strptr_PrintBash(temp,str);
17422 }
17423 if (!(row.generate_build == false)) {
17424 ch_RemoveAll(temp);
17425 bool_Print(row.generate_build, temp);
17426 str << " -generate_build:";
17427 strptr_PrintBash(temp,str);
17428 }
17429 if (!(row.build == false)) {
17430 ch_RemoveAll(temp);
17431 bool_Print(row.build, temp);
17432 str << " -build:";
17433 strptr_PrintBash(temp,str);
17434 }
17435 if (!(row.dhost.expr == "")) {
17436 ch_RemoveAll(temp);
17437 command::dhost_Print(const_cast<command::dcli&>(row), temp);
17438 str << " -dhost:";
17439 strptr_PrintBash(temp,str);
17440 }
17441 if (!(row.dctr.expr == "")) {
17442 ch_RemoveAll(temp);
17443 command::dctr_Print(const_cast<command::dcli&>(row), temp);
17444 str << " -dctr:";
17445 strptr_PrintBash(temp,str);
17446 }
17447 if (!(row.dctrhost.expr == "")) {
17448 ch_RemoveAll(temp);
17449 command::dctrhost_Print(const_cast<command::dcli&>(row), temp);
17450 str << " -dctrhost:";
17451 strptr_PrintBash(temp,str);
17452 }
17453 if (!(row.t == false)) {
17454 ch_RemoveAll(temp);
17455 bool_Print(row.t, temp);
17456 str << " -t:";
17457 strptr_PrintBash(temp,str);
17458 }
17459 if (!(row.q == false)) {
17460 ch_RemoveAll(temp);
17461 bool_Print(row.q, temp);
17462 str << " -q:";
17463 strptr_PrintBash(temp,str);
17464 }
17465 if (!(row.dry_run == false)) {
17466 ch_RemoveAll(temp);
17467 bool_Print(row.dry_run, temp);
17468 str << " -dry_run:";
17469 strptr_PrintBash(temp,str);
17470 }
17471}
17472
17473// --- command.dcli..GetAnon
17474algo::strptr command::dcli_GetAnon(command::dcli &parent, i32 idx) {
17475 (void)parent;//only to avoid -Wunused-parameter
17476 switch(idx) {
17477 case(0): return strptr("cmd", 3);
17478 default: return algo::strptr();
17479 }
17480}
17481
17482// --- command.dcli..NArgs
17483// Used with command lines
17484// Return # of command-line arguments that must follow this argument
17485// If FIELD is invalid, return -1
17486i32 command::dcli_NArgs(command::FieldId field, algo::strptr& out_dflt, bool* out_anon) {
17487 i32 retval = 1;
17488 switch (field) {
17489 case command_FieldId_in: { // $comment
17490 *out_anon = false;
17491 } break;
17492 case command_FieldId_cmd: { // $comment
17493 *out_anon = true;
17494 } break;
17495 case command_FieldId_cmd_dctr: { // $comment
17496 *out_anon = false;
17497 } break;
17498 case command_FieldId_config_ssh: { // $comment
17499 *out_anon = false;
17500 retval=0;
17501 out_dflt="Y";
17502 } break;
17503 case command_FieldId_config_ssh_vpn: { // bool: no argument required but value may be specified as config_ssh:Y
17504 *out_anon = false;
17505 retval=0;
17506 out_dflt="Y";
17507 } break;
17508 case command_FieldId_clean_run: { // bool: no argument required but value may be specified as config_ssh_vpn:Y
17509 *out_anon = false;
17510 retval=0;
17511 out_dflt="Y";
17512 } break;
17513 case command_FieldId_shell: { // bool: no argument required but value may be specified as clean_run:Y
17514 *out_anon = false;
17515 retval=0;
17516 out_dflt="Y";
17517 } break;
17518 case command_FieldId_inspect: { // bool: no argument required but value may be specified as shell:Y
17519 *out_anon = false;
17520 retval=0;
17521 out_dflt="Y";
17522 } break;
17523 case command_FieldId_logs: { // bool: no argument required but value may be specified as inspect:Y
17524 *out_anon = false;
17525 retval=0;
17526 out_dflt="Y";
17527 } break;
17528 case command_FieldId_generate_build: { // bool: no argument required but value may be specified as logs:Y
17529 *out_anon = false;
17530 retval=0;
17531 out_dflt="Y";
17532 } break;
17533 case command_FieldId_build: { // bool: no argument required but value may be specified as generate_build:Y
17534 *out_anon = false;
17535 retval=0;
17536 out_dflt="Y";
17537 } break;
17538 case command_FieldId_dhost: { // bool: no argument required but value may be specified as build:Y
17539 *out_anon = false;
17540 } break;
17541 case command_FieldId_dctr: { // bool: no argument required but value may be specified as build:Y
17542 *out_anon = false;
17543 } break;
17544 case command_FieldId_dctrhost: { // bool: no argument required but value may be specified as build:Y
17545 *out_anon = false;
17546 } break;
17547 case command_FieldId_t: { // bool: no argument required but value may be specified as build:Y
17548 *out_anon = false;
17549 retval=0;
17550 out_dflt="Y";
17551 } break;
17552 case command_FieldId_q: { // bool: no argument required but value may be specified as t:Y
17553 *out_anon = false;
17554 retval=0;
17555 out_dflt="Y";
17556 } break;
17557 case command_FieldId_dry_run: { // bool: no argument required but value may be specified as q:Y
17558 *out_anon = false;
17559 retval=0;
17560 out_dflt="Y";
17561 } break;
17562 default:
17563 retval=-1; // unrecognized
17564 }
17565 return retval;
17566}
17567
17568// --- command.dcli_ed..ReadFieldMaybe
17569bool command::dcli_ed_ReadFieldMaybe(command::dcli_ed& parent, algo::strptr field, algo::strptr strval) {
17570 bool retval = true;
17571 command::FieldId field_id;
17572 (void)value_SetStrptrMaybe(field_id,field);
17573 switch(field_id) {
17574 case command_FieldId_in: {
17575 retval = algo::cstring_ReadStrptrMaybe(parent.in, strval);
17576 break;
17577 }
17578 case command_FieldId_script_dir: {
17579 retval = algo::cstring_ReadStrptrMaybe(parent.script_dir, strval);
17580 break;
17581 }
17582 case command_FieldId_target: {
17583 retval = algo::Smallstr50_ReadStrptrMaybe(parent.target, strval);
17584 break;
17585 }
17586 case command_FieldId_dctr: {
17587 retval = algo::Smallstr50_ReadStrptrMaybe(parent.dctr, strval);
17588 break;
17589 }
17590 case command_FieldId_dhost: {
17591 retval = algo::Smallstr50_ReadStrptrMaybe(parent.dhost, strval);
17592 break;
17593 }
17594 case command_FieldId_dctrhost: {
17595 retval = algo::Smallstr50_ReadStrptrMaybe(parent.dctrhost, strval);
17596 break;
17597 }
17598 case command_FieldId_create: {
17599 retval = bool_ReadStrptrMaybe(parent.create, strval);
17600 break;
17601 }
17602 case command_FieldId_cloneto: {
17603 retval = algo::Smallstr50_ReadStrptrMaybe(parent.cloneto, strval);
17604 break;
17605 }
17606 case command_FieldId_renameto: {
17607 retval = algo::Smallstr50_ReadStrptrMaybe(parent.renameto, strval);
17608 break;
17609 }
17610 case command_FieldId_del: {
17611 retval = bool_ReadStrptrMaybe(parent.del, strval);
17612 break;
17613 }
17614 case command_FieldId_purge: {
17615 retval = bool_ReadStrptrMaybe(parent.purge, strval);
17616 break;
17617 }
17618 case command_FieldId_write: {
17619 retval = bool_ReadStrptrMaybe(parent.write, strval);
17620 break;
17621 }
17622 case command_FieldId_force: {
17623 retval = bool_ReadStrptrMaybe(parent.force, strval);
17624 break;
17625 }
17626 case command_FieldId_deep: {
17627 retval = bool_ReadStrptrMaybe(parent.deep, strval);
17628 break;
17629 }
17630 case command_FieldId_sync: {
17631 retval = bool_ReadStrptrMaybe(parent.sync, strval);
17632 break;
17633 }
17634 case command_FieldId_keep_files: {
17635 retval = bool_ReadStrptrMaybe(parent.keep_files, strval);
17636 break;
17637 }
17638 case command_FieldId_comment: {
17639 retval = algo::Comment_ReadStrptrMaybe(parent.comment, strval);
17640 break;
17641 }
17642 case command_FieldId_dctr_from: {
17643 retval = algo::cstring_ReadStrptrMaybe(parent.dctr_from, strval);
17644 break;
17645 }
17646 case command_FieldId_dhost_ip: {
17647 retval = algo::cstring_ReadStrptrMaybe(parent.dhost_ip, strval);
17648 break;
17649 }
17650 case command_FieldId_dhost_ext_ip: {
17651 retval = algo::cstring_ReadStrptrMaybe(parent.dhost_ext_ip, strval);
17652 break;
17653 }
17654 case command_FieldId_dhost_ext_port: {
17655 retval = algo::cstring_ReadStrptrMaybe(parent.dhost_ext_port, strval);
17656 break;
17657 }
17658 case command_FieldId_dhost_user: {
17659 retval = algo::cstring_ReadStrptrMaybe(parent.dhost_user, strval);
17660 break;
17661 }
17662 default: break;
17663 }
17664 if (!retval) {
17665 algo_lib::AppendErrtext("attr",field);
17666 }
17667 return retval;
17668}
17669
17670// --- command.dcli_ed..ReadTupleMaybe
17671// Read fields of command::dcli_ed from attributes of ascii tuple TUPLE
17672bool command::dcli_ed_ReadTupleMaybe(command::dcli_ed &parent, algo::Tuple &tuple) {
17673 bool retval = true;
17674 int anon_idx = 0;
17675 ind_beg(algo::Tuple_attrs_curs,attr,tuple) {
17676 if (ch_N(attr.name) == 0) {
17677 attr.name = dcli_ed_GetAnon(parent, anon_idx++);
17678 }
17679 retval = dcli_ed_ReadFieldMaybe(parent, attr.name, attr.value);
17680 if (!retval) {
17681 break;
17682 }
17683 }ind_end;
17684 return retval;
17685}
17686
17687// --- command.dcli_ed..Init
17688// Set all fields to initial values.
17689void command::dcli_ed_Init(command::dcli_ed& parent) {
17690 parent.in = algo::strptr("data");
17691 parent.script_dir = algo::strptr("docker");
17692 parent.target = algo::strptr("");
17693 parent.dctr = algo::strptr("");
17694 parent.dhost = algo::strptr("");
17695 parent.dctrhost = algo::strptr("");
17696 parent.create = bool(false);
17697 parent.cloneto = algo::strptr("");
17698 parent.renameto = algo::strptr("");
17699 parent.del = bool(false);
17700 parent.purge = bool(false);
17701 parent.write = bool(false);
17702 parent.force = bool(false);
17703 parent.deep = bool(false);
17704 parent.sync = bool(true);
17705 parent.keep_files = bool(false);
17706 parent.comment = algo::Comment("");
17707 parent.dctr_from = algo::strptr("ubuntu");
17708 parent.dhost_ip = algo::strptr("");
17709 parent.dhost_ext_ip = algo::strptr("");
17710 parent.dhost_ext_port = algo::strptr("3022");
17711 parent.dhost_user = algo::strptr("dcliusr");
17712}
17713
17714// --- command.dcli_ed..ToCmdline
17715// Convenience function that returns a full command line
17716// Assume command is in a directory called bin
17717tempstr command::dcli_ed_ToCmdline(command::dcli_ed& row) {
17718 tempstr ret;
17719 ret << "bin/dcli_ed ";
17720 dcli_ed_PrintArgv(row, ret);
17721 // inherit less intense verbose, debug options
17722 for (int i = 1; i < algo_lib::_db.cmdline.verbose; i++) {
17723 ret << " -verbose";
17724 }
17725 for (int i = 1; i < algo_lib::_db.cmdline.debug; i++) {
17726 ret << " -debug";
17727 }
17728 return ret;
17729}
17730
17731// --- command.dcli_ed..PrintArgv
17732// print string representation of ROW to string STR
17733// cfmt:command.dcli_ed.Argv printfmt:Tuple
17734void command::dcli_ed_PrintArgv(command::dcli_ed& row, algo::cstring& str) {
17735 algo::tempstr temp;
17736 (void)temp;
17737 (void)str;
17738 if (!(row.in == "data")) {
17739 ch_RemoveAll(temp);
17740 cstring_Print(row.in, temp);
17741 str << " -in:";
17742 strptr_PrintBash(temp,str);
17743 }
17744 if (!(row.script_dir == "docker")) {
17745 ch_RemoveAll(temp);
17746 cstring_Print(row.script_dir, temp);
17747 str << " -script_dir:";
17748 strptr_PrintBash(temp,str);
17749 }
17750 ch_RemoveAll(temp);
17751 Smallstr50_Print(row.target, temp);
17752 str << " -target:";
17753 strptr_PrintBash(temp,str);
17754 if (!(row.dctr == "")) {
17755 ch_RemoveAll(temp);
17756 Smallstr50_Print(row.dctr, temp);
17757 str << " -dctr:";
17758 strptr_PrintBash(temp,str);
17759 }
17760 if (!(row.dhost == "")) {
17761 ch_RemoveAll(temp);
17762 Smallstr50_Print(row.dhost, temp);
17763 str << " -dhost:";
17764 strptr_PrintBash(temp,str);
17765 }
17766 if (!(row.dctrhost == "")) {
17767 ch_RemoveAll(temp);
17768 Smallstr50_Print(row.dctrhost, temp);
17769 str << " -dctrhost:";
17770 strptr_PrintBash(temp,str);
17771 }
17772 if (!(row.create == false)) {
17773 ch_RemoveAll(temp);
17774 bool_Print(row.create, temp);
17775 str << " -create:";
17776 strptr_PrintBash(temp,str);
17777 }
17778 if (!(row.cloneto == "")) {
17779 ch_RemoveAll(temp);
17780 Smallstr50_Print(row.cloneto, temp);
17781 str << " -cloneto:";
17782 strptr_PrintBash(temp,str);
17783 }
17784 if (!(row.renameto == "")) {
17785 ch_RemoveAll(temp);
17786 Smallstr50_Print(row.renameto, temp);
17787 str << " -renameto:";
17788 strptr_PrintBash(temp,str);
17789 }
17790 if (!(row.del == false)) {
17791 ch_RemoveAll(temp);
17792 bool_Print(row.del, temp);
17793 str << " -del:";
17794 strptr_PrintBash(temp,str);
17795 }
17796 if (!(row.purge == false)) {
17797 ch_RemoveAll(temp);
17798 bool_Print(row.purge, temp);
17799 str << " -purge:";
17800 strptr_PrintBash(temp,str);
17801 }
17802 if (!(row.write == false)) {
17803 ch_RemoveAll(temp);
17804 bool_Print(row.write, temp);
17805 str << " -write:";
17806 strptr_PrintBash(temp,str);
17807 }
17808 if (!(row.force == false)) {
17809 ch_RemoveAll(temp);
17810 bool_Print(row.force, temp);
17811 str << " -force:";
17812 strptr_PrintBash(temp,str);
17813 }
17814 if (!(row.deep == false)) {
17815 ch_RemoveAll(temp);
17816 bool_Print(row.deep, temp);
17817 str << " -deep:";
17818 strptr_PrintBash(temp,str);
17819 }
17820 if (!(row.sync == true)) {
17821 ch_RemoveAll(temp);
17822 bool_Print(row.sync, temp);
17823 str << " -sync:";
17824 strptr_PrintBash(temp,str);
17825 }
17826 if (!(row.keep_files == false)) {
17827 ch_RemoveAll(temp);
17828 bool_Print(row.keep_files, temp);
17829 str << " -keep_files:";
17830 strptr_PrintBash(temp,str);
17831 }
17832 if (!(row.comment == "")) {
17833 ch_RemoveAll(temp);
17834 Comment_Print(row.comment, temp);
17835 str << " -comment:";
17836 strptr_PrintBash(temp,str);
17837 }
17838 if (!(row.dctr_from == "ubuntu")) {
17839 ch_RemoveAll(temp);
17840 cstring_Print(row.dctr_from, temp);
17841 str << " -dctr_from:";
17842 strptr_PrintBash(temp,str);
17843 }
17844 if (!(row.dhost_ip == "")) {
17845 ch_RemoveAll(temp);
17846 cstring_Print(row.dhost_ip, temp);
17847 str << " -dhost_ip:";
17848 strptr_PrintBash(temp,str);
17849 }
17850 if (!(row.dhost_ext_ip == "")) {
17851 ch_RemoveAll(temp);
17852 cstring_Print(row.dhost_ext_ip, temp);
17853 str << " -dhost_ext_ip:";
17854 strptr_PrintBash(temp,str);
17855 }
17856 if (!(row.dhost_ext_port == "3022")) {
17857 ch_RemoveAll(temp);
17858 cstring_Print(row.dhost_ext_port, temp);
17859 str << " -dhost_ext_port:";
17860 strptr_PrintBash(temp,str);
17861 }
17862 if (!(row.dhost_user == "dcliusr")) {
17863 ch_RemoveAll(temp);
17864 cstring_Print(row.dhost_user, temp);
17865 str << " -dhost_user:";
17866 strptr_PrintBash(temp,str);
17867 }
17868}
17869
17870// --- command.dcli_ed..Print
17871// print string representation of ROW to string STR
17872// cfmt:command.dcli_ed.String printfmt:Tuple
17873void command::dcli_ed_Print(command::dcli_ed& row, algo::cstring& str) {
17874 algo::tempstr temp;
17875 str << "command.dcli_ed";
17876
17877 algo::cstring_Print(row.in, temp);
17878 PrintAttrSpaceReset(str,"in", temp);
17879
17880 algo::cstring_Print(row.script_dir, temp);
17881 PrintAttrSpaceReset(str,"script_dir", temp);
17882
17883 algo::Smallstr50_Print(row.target, temp);
17884 PrintAttrSpaceReset(str,"target", temp);
17885
17886 algo::Smallstr50_Print(row.dctr, temp);
17887 PrintAttrSpaceReset(str,"dctr", temp);
17888
17889 algo::Smallstr50_Print(row.dhost, temp);
17890 PrintAttrSpaceReset(str,"dhost", temp);
17891
17892 algo::Smallstr50_Print(row.dctrhost, temp);
17893 PrintAttrSpaceReset(str,"dctrhost", temp);
17894
17895 bool_Print(row.create, temp);
17896 PrintAttrSpaceReset(str,"create", temp);
17897
17898 algo::Smallstr50_Print(row.cloneto, temp);
17899 PrintAttrSpaceReset(str,"cloneto", temp);
17900
17901 algo::Smallstr50_Print(row.renameto, temp);
17902 PrintAttrSpaceReset(str,"renameto", temp);
17903
17904 bool_Print(row.del, temp);
17905 PrintAttrSpaceReset(str,"del", temp);
17906
17907 bool_Print(row.purge, temp);
17908 PrintAttrSpaceReset(str,"purge", temp);
17909
17910 bool_Print(row.write, temp);
17911 PrintAttrSpaceReset(str,"write", temp);
17912
17913 bool_Print(row.force, temp);
17914 PrintAttrSpaceReset(str,"force", temp);
17915
17916 bool_Print(row.deep, temp);
17917 PrintAttrSpaceReset(str,"deep", temp);
17918
17919 bool_Print(row.sync, temp);
17920 PrintAttrSpaceReset(str,"sync", temp);
17921
17922 bool_Print(row.keep_files, temp);
17923 PrintAttrSpaceReset(str,"keep_files", temp);
17924
17925 algo::Comment_Print(row.comment, temp);
17926 PrintAttrSpaceReset(str,"comment", temp);
17927
17928 algo::cstring_Print(row.dctr_from, temp);
17929 PrintAttrSpaceReset(str,"dctr_from", temp);
17930
17931 algo::cstring_Print(row.dhost_ip, temp);
17932 PrintAttrSpaceReset(str,"dhost_ip", temp);
17933
17934 algo::cstring_Print(row.dhost_ext_ip, temp);
17935 PrintAttrSpaceReset(str,"dhost_ext_ip", temp);
17936
17937 algo::cstring_Print(row.dhost_ext_port, temp);
17938 PrintAttrSpaceReset(str,"dhost_ext_port", temp);
17939
17940 algo::cstring_Print(row.dhost_user, temp);
17941 PrintAttrSpaceReset(str,"dhost_user", temp);
17942}
17943
17944// --- command.dcli_ed..GetAnon
17945algo::strptr command::dcli_ed_GetAnon(command::dcli_ed &parent, i32 idx) {
17946 (void)parent;//only to avoid -Wunused-parameter
17947 switch(idx) {
17948 case(0): return strptr("target", 6);
17949 default: return algo::strptr();
17950 }
17951}
17952
17953// --- command.dcli_ed..NArgs
17954// Used with command lines
17955// Return # of command-line arguments that must follow this argument
17956// If FIELD is invalid, return -1
17957i32 command::dcli_ed_NArgs(command::FieldId field, algo::strptr& out_dflt, bool* out_anon) {
17958 i32 retval = 1;
17959 switch (field) {
17960 case command_FieldId_in: { // $comment
17961 *out_anon = false;
17962 } break;
17963 case command_FieldId_script_dir: { // $comment
17964 *out_anon = false;
17965 } break;
17966 case command_FieldId_target: { // $comment
17967 *out_anon = true;
17968 } break;
17969 case command_FieldId_dctr: { // $comment
17970 *out_anon = false;
17971 } break;
17972 case command_FieldId_dhost: { // $comment
17973 *out_anon = false;
17974 } break;
17975 case command_FieldId_dctrhost: { // $comment
17976 *out_anon = false;
17977 } break;
17978 case command_FieldId_create: { // $comment
17979 *out_anon = false;
17980 retval=0;
17981 out_dflt="Y";
17982 } break;
17983 case command_FieldId_cloneto: { // bool: no argument required but value may be specified as create:Y
17984 *out_anon = false;
17985 } break;
17986 case command_FieldId_renameto: { // bool: no argument required but value may be specified as create:Y
17987 *out_anon = false;
17988 } break;
17989 case command_FieldId_del: { // bool: no argument required but value may be specified as create:Y
17990 *out_anon = false;
17991 retval=0;
17992 out_dflt="Y";
17993 } break;
17994 case command_FieldId_purge: { // bool: no argument required but value may be specified as del:Y
17995 *out_anon = false;
17996 retval=0;
17997 out_dflt="Y";
17998 } break;
17999 case command_FieldId_write: { // bool: no argument required but value may be specified as purge:Y
18000 *out_anon = false;
18001 retval=0;
18002 out_dflt="Y";
18003 } break;
18004 case command_FieldId_force: { // bool: no argument required but value may be specified as write:Y
18005 *out_anon = false;
18006 retval=0;
18007 out_dflt="Y";
18008 } break;
18009 case command_FieldId_deep: { // bool: no argument required but value may be specified as force:Y
18010 *out_anon = false;
18011 retval=0;
18012 out_dflt="Y";
18013 } break;
18014 case command_FieldId_sync: { // bool: no argument required but value may be specified as deep:Y
18015 *out_anon = false;
18016 retval=0;
18017 out_dflt="Y";
18018 } break;
18019 case command_FieldId_keep_files: { // bool: no argument required but value may be specified as sync:Y
18020 *out_anon = false;
18021 retval=0;
18022 out_dflt="Y";
18023 } break;
18024 case command_FieldId_comment: { // bool: no argument required but value may be specified as keep_files:Y
18025 *out_anon = false;
18026 } break;
18027 case command_FieldId_dctr_from: { // bool: no argument required but value may be specified as keep_files:Y
18028 *out_anon = false;
18029 } break;
18030 case command_FieldId_dhost_ip: { // bool: no argument required but value may be specified as keep_files:Y
18031 *out_anon = false;
18032 } break;
18033 case command_FieldId_dhost_ext_ip: { // bool: no argument required but value may be specified as keep_files:Y
18034 *out_anon = false;
18035 } break;
18036 case command_FieldId_dhost_ext_port: { // bool: no argument required but value may be specified as keep_files:Y
18037 *out_anon = false;
18038 } break;
18039 case command_FieldId_dhost_user: { // bool: no argument required but value may be specified as keep_files:Y
18040 *out_anon = false;
18041 } break;
18042 default:
18043 retval=-1; // unrecognized
18044 }
18045 return retval;
18046}
18047
18048// --- command.dcli_ed_proc.dcli_ed.Start
18049// Start subprocess
18050// If subprocess already running, do nothing. Otherwise, start it
18051int command::dcli_ed_Start(command::dcli_ed_proc& parent) {
18052 int retval = 0;
18053 if (parent.pid == 0) {
18054 verblog(dcli_ed_ToCmdline(parent)); // maybe print command
18055#ifdef WIN32
18056 algo_lib::ResolveExecFname(parent.path);
18057 tempstr cmdline(dcli_ed_ToCmdline(parent));
18058 parent.pid = dospawn(Zeroterm(parent.path),Zeroterm(cmdline),parent.timeout,parent.fstdin,parent.fstdout,parent.fstderr);
18059#else
18060 parent.pid = fork();
18061 if (parent.pid == 0) { // child
18062 algo_lib::DieWithParent();
18063 if (parent.timeout > 0) {
18064 alarm(parent.timeout);
18065 }
18066 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstdin , 0);
18067 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstdout, 1);
18068 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstderr, 2);
18069 if (retval==0) retval= dcli_ed_Execv(parent);
18070 if (retval != 0) { // if start fails, print error
18071 int err=errno;
18072 prerr("command.dcli_ed_execv"
18073 <<Keyval("errno",err)
18074 <<Keyval("errstr",strerror(err))
18075 <<Keyval("comment","Execv failed"));
18076 }
18077 _exit(127); // if failed to start, exit anyway
18078 } else if (parent.pid == -1) {
18079 retval = errno; // failed to fork
18080 }
18081#endif
18082 }
18083 parent.status = parent.pid > 0 ? 0 : -1; // if didn't start, set error status
18084 return retval;
18085}
18086
18087// --- command.dcli_ed_proc.dcli_ed.StartRead
18088// Start subprocess & Read output
18089algo::Fildes command::dcli_ed_StartRead(command::dcli_ed_proc& parent, algo_lib::FFildes &read) {
18090 int pipefd[2];
18091 int rc=pipe(pipefd);
18092 (void)rc;
18093 read.fd.value = pipefd[0];
18094 parent.fstdout << ">&" << pipefd[1];
18095 dcli_ed_Start(parent);
18096 (void)close(pipefd[1]);
18097 return read.fd;
18098}
18099
18100// --- command.dcli_ed_proc.dcli_ed.Kill
18101// Kill subprocess and wait
18102void command::dcli_ed_Kill(command::dcli_ed_proc& parent) {
18103 if (parent.pid != 0) {
18104 kill(parent.pid,9);
18105 dcli_ed_Wait(parent);
18106 }
18107}
18108
18109// --- command.dcli_ed_proc.dcli_ed.Wait
18110// Wait for subprocess to return
18111void command::dcli_ed_Wait(command::dcli_ed_proc& parent) {
18112 if (parent.pid > 0) {
18113 int wait_flags = 0;
18114 int wait_status = 0;
18115 int rc = -1;
18116 do {
18117 // really wait for subprocess to exit
18118 rc = waitpid(parent.pid,&wait_status,wait_flags);
18119 } while (rc==-1 && errno==EINTR);
18120 if (rc == parent.pid) {
18121 parent.status = wait_status;
18122 parent.pid = 0;
18123 }
18124 }
18125}
18126
18127// --- command.dcli_ed_proc.dcli_ed.Exec
18128// Start + Wait
18129// Execute subprocess and return exit code
18130int command::dcli_ed_Exec(command::dcli_ed_proc& parent) {
18131 dcli_ed_Start(parent);
18132 dcli_ed_Wait(parent);
18133 return parent.status;
18134}
18135
18136// --- command.dcli_ed_proc.dcli_ed.ExecX
18137// Start + Wait, throw exception on error
18138// Execute subprocess; throw human-readable exception on error
18139void command::dcli_ed_ExecX(command::dcli_ed_proc& parent) {
18140 int rc = dcli_ed_Exec(parent);
18141 vrfy(rc==0, tempstr() << "algo_lib.exec" << Keyval("cmd",dcli_ed_ToCmdline(parent))
18142 << Keyval("comment",algo::DescribeWaitStatus(parent.status)));
18143}
18144
18145// --- command.dcli_ed_proc.dcli_ed.Execv
18146// Call execv()
18147// Call execv with specified parameters
18148int command::dcli_ed_Execv(command::dcli_ed_proc& parent) {
18149 int ret = 0;
18150 algo::StringAry args;
18151 dcli_ed_ToArgv(parent, args);
18152 char **argv = (char**)alloca((ary_N(args)+1)*sizeof(*argv));
18153 ind_beg(algo::StringAry_ary_curs,arg,args) {
18154 argv[ind_curs(arg).index] = Zeroterm(arg);
18155 }ind_end;
18156 argv[ary_N(args)] = NULL;
18157 // if parent.path is relative, search for it in PATH
18158 algo_lib::ResolveExecFname(parent.path);
18159 ret = execv(Zeroterm(parent.path),argv);
18160 return ret;
18161}
18162
18163// --- command.dcli_ed_proc.dcli_ed.ToCmdline
18164algo::tempstr command::dcli_ed_ToCmdline(command::dcli_ed_proc& parent) {
18165 algo::tempstr retval;
18166 retval << parent.path << " ";
18167 command::dcli_ed_PrintArgv(parent.cmd,retval);
18168 if (ch_N(parent.fstdin)) {
18169 retval << " " << parent.fstdin;
18170 }
18171 if (ch_N(parent.fstdout)) {
18172 retval << " " << parent.fstdout;
18173 }
18174 if (ch_N(parent.fstderr)) {
18175 retval << " 2" << parent.fstderr;
18176 }
18177 return retval;
18178}
18179
18180// --- command.dcli_ed_proc.dcli_ed.ToArgv
18181// Form array from the command line
18182void command::dcli_ed_ToArgv(command::dcli_ed_proc& parent, algo::StringAry& args) {
18183 ary_RemoveAll(args);
18184 ary_Alloc(args) << parent.path;
18185
18186 if (parent.cmd.in != "data") {
18187 cstring *arg = &ary_Alloc(args);
18188 *arg << "-in:";
18189 cstring_Print(parent.cmd.in, *arg);
18190 }
18191
18192 if (parent.cmd.script_dir != "docker") {
18193 cstring *arg = &ary_Alloc(args);
18194 *arg << "-script_dir:";
18195 cstring_Print(parent.cmd.script_dir, *arg);
18196 }
18197
18198 if (parent.cmd.target != "") {
18199 cstring *arg = &ary_Alloc(args);
18200 *arg << "-target:";
18201 Smallstr50_Print(parent.cmd.target, *arg);
18202 }
18203
18204 if (parent.cmd.dctr != "") {
18205 cstring *arg = &ary_Alloc(args);
18206 *arg << "-dctr:";
18207 Smallstr50_Print(parent.cmd.dctr, *arg);
18208 }
18209
18210 if (parent.cmd.dhost != "") {
18211 cstring *arg = &ary_Alloc(args);
18212 *arg << "-dhost:";
18213 Smallstr50_Print(parent.cmd.dhost, *arg);
18214 }
18215
18216 if (parent.cmd.dctrhost != "") {
18217 cstring *arg = &ary_Alloc(args);
18218 *arg << "-dctrhost:";
18219 Smallstr50_Print(parent.cmd.dctrhost, *arg);
18220 }
18221
18222 if (parent.cmd.create != false) {
18223 cstring *arg = &ary_Alloc(args);
18224 *arg << "-create:";
18225 bool_Print(parent.cmd.create, *arg);
18226 }
18227
18228 if (parent.cmd.cloneto != "") {
18229 cstring *arg = &ary_Alloc(args);
18230 *arg << "-cloneto:";
18231 Smallstr50_Print(parent.cmd.cloneto, *arg);
18232 }
18233
18234 if (parent.cmd.renameto != "") {
18235 cstring *arg = &ary_Alloc(args);
18236 *arg << "-renameto:";
18237 Smallstr50_Print(parent.cmd.renameto, *arg);
18238 }
18239
18240 if (parent.cmd.del != false) {
18241 cstring *arg = &ary_Alloc(args);
18242 *arg << "-del:";
18243 bool_Print(parent.cmd.del, *arg);
18244 }
18245
18246 if (parent.cmd.purge != false) {
18247 cstring *arg = &ary_Alloc(args);
18248 *arg << "-purge:";
18249 bool_Print(parent.cmd.purge, *arg);
18250 }
18251
18252 if (parent.cmd.write != false) {
18253 cstring *arg = &ary_Alloc(args);
18254 *arg << "-write:";
18255 bool_Print(parent.cmd.write, *arg);
18256 }
18257
18258 if (parent.cmd.force != false) {
18259 cstring *arg = &ary_Alloc(args);
18260 *arg << "-force:";
18261 bool_Print(parent.cmd.force, *arg);
18262 }
18263
18264 if (parent.cmd.deep != false) {
18265 cstring *arg = &ary_Alloc(args);
18266 *arg << "-deep:";
18267 bool_Print(parent.cmd.deep, *arg);
18268 }
18269
18270 if (parent.cmd.sync != true) {
18271 cstring *arg = &ary_Alloc(args);
18272 *arg << "-sync:";
18273 bool_Print(parent.cmd.sync, *arg);
18274 }
18275
18276 if (parent.cmd.keep_files != false) {
18277 cstring *arg = &ary_Alloc(args);
18278 *arg << "-keep_files:";
18279 bool_Print(parent.cmd.keep_files, *arg);
18280 }
18281
18282 if (parent.cmd.comment != "") {
18283 cstring *arg = &ary_Alloc(args);
18284 *arg << "-comment:";
18285 Comment_Print(parent.cmd.comment, *arg);
18286 }
18287
18288 if (parent.cmd.dctr_from != "ubuntu") {
18289 cstring *arg = &ary_Alloc(args);
18290 *arg << "-dctr_from:";
18291 cstring_Print(parent.cmd.dctr_from, *arg);
18292 }
18293
18294 if (parent.cmd.dhost_ip != "") {
18295 cstring *arg = &ary_Alloc(args);
18296 *arg << "-dhost_ip:";
18297 cstring_Print(parent.cmd.dhost_ip, *arg);
18298 }
18299
18300 if (parent.cmd.dhost_ext_ip != "") {
18301 cstring *arg = &ary_Alloc(args);
18302 *arg << "-dhost_ext_ip:";
18303 cstring_Print(parent.cmd.dhost_ext_ip, *arg);
18304 }
18305
18306 if (parent.cmd.dhost_ext_port != "3022") {
18307 cstring *arg = &ary_Alloc(args);
18308 *arg << "-dhost_ext_port:";
18309 cstring_Print(parent.cmd.dhost_ext_port, *arg);
18310 }
18311
18312 if (parent.cmd.dhost_user != "dcliusr") {
18313 cstring *arg = &ary_Alloc(args);
18314 *arg << "-dhost_user:";
18315 cstring_Print(parent.cmd.dhost_user, *arg);
18316 }
18317 for (int i=1; i < algo_lib::_db.cmdline.verbose; ++i) {
18318 ary_Alloc(args) << "-verbose";
18319 }
18320}
18321
18322// --- command.dcli_ed_proc..Uninit
18323void command::dcli_ed_proc_Uninit(command::dcli_ed_proc& parent) {
18324 command::dcli_ed_proc &row = parent; (void)row;
18325
18326 // command.dcli_ed_proc.dcli_ed.Uninit (Exec) //
18327 dcli_ed_Kill(parent); // kill child, ensure forward progress
18328}
18329
18330// --- command.dcli_proc.dcli.Start
18331// Start subprocess
18332// If subprocess already running, do nothing. Otherwise, start it
18333int command::dcli_Start(command::dcli_proc& parent) {
18334 int retval = 0;
18335 if (parent.pid == 0) {
18336 verblog(dcli_ToCmdline(parent)); // maybe print command
18337#ifdef WIN32
18338 algo_lib::ResolveExecFname(parent.path);
18339 tempstr cmdline(dcli_ToCmdline(parent));
18340 parent.pid = dospawn(Zeroterm(parent.path),Zeroterm(cmdline),parent.timeout,parent.fstdin,parent.fstdout,parent.fstderr);
18341#else
18342 parent.pid = fork();
18343 if (parent.pid == 0) { // child
18344 algo_lib::DieWithParent();
18345 if (parent.timeout > 0) {
18346 alarm(parent.timeout);
18347 }
18348 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstdin , 0);
18349 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstdout, 1);
18350 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstderr, 2);
18351 if (retval==0) retval= dcli_Execv(parent);
18352 if (retval != 0) { // if start fails, print error
18353 int err=errno;
18354 prerr("command.dcli_execv"
18355 <<Keyval("errno",err)
18356 <<Keyval("errstr",strerror(err))
18357 <<Keyval("comment","Execv failed"));
18358 }
18359 _exit(127); // if failed to start, exit anyway
18360 } else if (parent.pid == -1) {
18361 retval = errno; // failed to fork
18362 }
18363#endif
18364 }
18365 parent.status = parent.pid > 0 ? 0 : -1; // if didn't start, set error status
18366 return retval;
18367}
18368
18369// --- command.dcli_proc.dcli.StartRead
18370// Start subprocess & Read output
18371algo::Fildes command::dcli_StartRead(command::dcli_proc& parent, algo_lib::FFildes &read) {
18372 int pipefd[2];
18373 int rc=pipe(pipefd);
18374 (void)rc;
18375 read.fd.value = pipefd[0];
18376 parent.fstdout << ">&" << pipefd[1];
18377 dcli_Start(parent);
18378 (void)close(pipefd[1]);
18379 return read.fd;
18380}
18381
18382// --- command.dcli_proc.dcli.Kill
18383// Kill subprocess and wait
18384void command::dcli_Kill(command::dcli_proc& parent) {
18385 if (parent.pid != 0) {
18386 kill(parent.pid,9);
18387 dcli_Wait(parent);
18388 }
18389}
18390
18391// --- command.dcli_proc.dcli.Wait
18392// Wait for subprocess to return
18393void command::dcli_Wait(command::dcli_proc& parent) {
18394 if (parent.pid > 0) {
18395 int wait_flags = 0;
18396 int wait_status = 0;
18397 int rc = -1;
18398 do {
18399 // really wait for subprocess to exit
18400 rc = waitpid(parent.pid,&wait_status,wait_flags);
18401 } while (rc==-1 && errno==EINTR);
18402 if (rc == parent.pid) {
18403 parent.status = wait_status;
18404 parent.pid = 0;
18405 }
18406 }
18407}
18408
18409// --- command.dcli_proc.dcli.Exec
18410// Start + Wait
18411// Execute subprocess and return exit code
18412int command::dcli_Exec(command::dcli_proc& parent) {
18413 dcli_Start(parent);
18414 dcli_Wait(parent);
18415 return parent.status;
18416}
18417
18418// --- command.dcli_proc.dcli.ExecX
18419// Start + Wait, throw exception on error
18420// Execute subprocess; throw human-readable exception on error
18421void command::dcli_ExecX(command::dcli_proc& parent) {
18422 int rc = dcli_Exec(parent);
18423 vrfy(rc==0, tempstr() << "algo_lib.exec" << Keyval("cmd",dcli_ToCmdline(parent))
18424 << Keyval("comment",algo::DescribeWaitStatus(parent.status)));
18425}
18426
18427// --- command.dcli_proc.dcli.Execv
18428// Call execv()
18429// Call execv with specified parameters
18430int command::dcli_Execv(command::dcli_proc& parent) {
18431 int ret = 0;
18432 algo::StringAry args;
18433 dcli_ToArgv(parent, args);
18434 char **argv = (char**)alloca((ary_N(args)+1)*sizeof(*argv));
18435 ind_beg(algo::StringAry_ary_curs,arg,args) {
18436 argv[ind_curs(arg).index] = Zeroterm(arg);
18437 }ind_end;
18438 argv[ary_N(args)] = NULL;
18439 // if parent.path is relative, search for it in PATH
18440 algo_lib::ResolveExecFname(parent.path);
18441 ret = execv(Zeroterm(parent.path),argv);
18442 return ret;
18443}
18444
18445// --- command.dcli_proc.dcli.ToCmdline
18446algo::tempstr command::dcli_ToCmdline(command::dcli_proc& parent) {
18447 algo::tempstr retval;
18448 retval << parent.path << " ";
18449 command::dcli_PrintArgv(parent.cmd,retval);
18450 if (ch_N(parent.fstdin)) {
18451 retval << " " << parent.fstdin;
18452 }
18453 if (ch_N(parent.fstdout)) {
18454 retval << " " << parent.fstdout;
18455 }
18456 if (ch_N(parent.fstderr)) {
18457 retval << " 2" << parent.fstderr;
18458 }
18459 return retval;
18460}
18461
18462// --- command.dcli_proc.dcli.ToArgv
18463// Form array from the command line
18464void command::dcli_ToArgv(command::dcli_proc& parent, algo::StringAry& args) {
18465 ary_RemoveAll(args);
18466 ary_Alloc(args) << parent.path;
18467
18468 if (parent.cmd.in != "data") {
18469 cstring *arg = &ary_Alloc(args);
18470 *arg << "-in:";
18471 cstring_Print(parent.cmd.in, *arg);
18472 }
18473
18474 if (parent.cmd.cmd != "") {
18475 cstring *arg = &ary_Alloc(args);
18476 *arg << "-cmd:";
18477 cstring_Print(parent.cmd.cmd, *arg);
18478 }
18479
18480 if (parent.cmd.cmd_dctr != "") {
18481 cstring *arg = &ary_Alloc(args);
18482 *arg << "-cmd_dctr:";
18483 cstring_Print(parent.cmd.cmd_dctr, *arg);
18484 }
18485
18486 if (parent.cmd.config_ssh != false) {
18487 cstring *arg = &ary_Alloc(args);
18488 *arg << "-config_ssh:";
18489 bool_Print(parent.cmd.config_ssh, *arg);
18490 }
18491
18492 if (parent.cmd.config_ssh_vpn != false) {
18493 cstring *arg = &ary_Alloc(args);
18494 *arg << "-config_ssh_vpn:";
18495 bool_Print(parent.cmd.config_ssh_vpn, *arg);
18496 }
18497
18498 if (parent.cmd.clean_run != false) {
18499 cstring *arg = &ary_Alloc(args);
18500 *arg << "-clean_run:";
18501 bool_Print(parent.cmd.clean_run, *arg);
18502 }
18503
18504 if (parent.cmd.shell != false) {
18505 cstring *arg = &ary_Alloc(args);
18506 *arg << "-shell:";
18507 bool_Print(parent.cmd.shell, *arg);
18508 }
18509
18510 if (parent.cmd.inspect != false) {
18511 cstring *arg = &ary_Alloc(args);
18512 *arg << "-inspect:";
18513 bool_Print(parent.cmd.inspect, *arg);
18514 }
18515
18516 if (parent.cmd.logs != false) {
18517 cstring *arg = &ary_Alloc(args);
18518 *arg << "-logs:";
18519 bool_Print(parent.cmd.logs, *arg);
18520 }
18521
18522 if (parent.cmd.generate_build != false) {
18523 cstring *arg = &ary_Alloc(args);
18524 *arg << "-generate_build:";
18525 bool_Print(parent.cmd.generate_build, *arg);
18526 }
18527
18528 if (parent.cmd.build != false) {
18529 cstring *arg = &ary_Alloc(args);
18530 *arg << "-build:";
18531 bool_Print(parent.cmd.build, *arg);
18532 }
18533
18534 if (parent.cmd.dhost.expr != "") {
18535 cstring *arg = &ary_Alloc(args);
18536 *arg << "-dhost:";
18537 command::dhost_Print(parent.cmd, *arg);
18538 }
18539
18540 if (parent.cmd.dctr.expr != "") {
18541 cstring *arg = &ary_Alloc(args);
18542 *arg << "-dctr:";
18543 command::dctr_Print(parent.cmd, *arg);
18544 }
18545
18546 if (parent.cmd.dctrhost.expr != "") {
18547 cstring *arg = &ary_Alloc(args);
18548 *arg << "-dctrhost:";
18549 command::dctrhost_Print(parent.cmd, *arg);
18550 }
18551
18552 if (parent.cmd.t != false) {
18553 cstring *arg = &ary_Alloc(args);
18554 *arg << "-t:";
18555 bool_Print(parent.cmd.t, *arg);
18556 }
18557
18558 if (parent.cmd.q != false) {
18559 cstring *arg = &ary_Alloc(args);
18560 *arg << "-q:";
18561 bool_Print(parent.cmd.q, *arg);
18562 }
18563
18564 if (parent.cmd.dry_run != false) {
18565 cstring *arg = &ary_Alloc(args);
18566 *arg << "-dry_run:";
18567 bool_Print(parent.cmd.dry_run, *arg);
18568 }
18569 for (int i=1; i < algo_lib::_db.cmdline.verbose; ++i) {
18570 ary_Alloc(args) << "-verbose";
18571 }
18572}
18573
18574// --- command.dcli_proc..Uninit
18575void command::dcli_proc_Uninit(command::dcli_proc& parent) {
18576 command::dcli_proc &row = parent; (void)row;
18577
18578 // command.dcli_proc.dcli.Uninit (Exec) //
18579 dcli_Kill(parent); // kill child, ensure forward progress
18580}
18581
18582// --- command.fast.enc.ToCstr
18583// Convert numeric value of field to one of predefined string constants.
18584// If string is found, return a static C string. Otherwise, return NULL.
18585const char* command::enc_ToCstr(const command::fast& parent) {
18586 const char *ret = NULL;
18587 switch(enc_GetEnum(parent)) {
18588 case command_fast_enc_none : ret = "none"; break;
18589 case command_fast_enc_unsigned : ret = "unsigned"; break;
18590 case command_fast_enc_signed : ret = "signed"; break;
18591 case command_fast_enc_string : ret = "string"; break;
18592 case command_fast_enc_bytevector : ret = "bytevector"; break;
18593 case command_fast_enc_scaled : ret = "scaled"; break;
18594 case command_fast_enc_pmap : ret = "pmap"; break;
18595 }
18596 return ret;
18597}
18598
18599// --- command.fast.enc.Print
18600// Convert enc to a string. First, attempt conversion to a known string.
18601// If no string matches, print enc as a numeric value.
18602void command::enc_Print(const command::fast& parent, algo::cstring &lhs) {
18603 const char *strval = enc_ToCstr(parent);
18604 if (strval) {
18605 lhs << strval;
18606 } else {
18607 lhs << parent.enc;
18608 }
18609}
18610
18611// --- command.fast.enc.SetStrptrMaybe
18612// Convert string to field.
18613// If the string is invalid, do not modify field and return false.
18614// In case of success, return true
18615bool command::enc_SetStrptrMaybe(command::fast& parent, algo::strptr rhs) {
18616 bool ret = false;
18617 switch (elems_N(rhs)) {
18618 case 4: {
18619 switch (u64(algo::ReadLE32(rhs.elems))) {
18620 case LE_STR4('n','o','n','e'): {
18621 enc_SetEnum(parent,command_fast_enc_none); ret = true; break;
18622 }
18623 case LE_STR4('p','m','a','p'): {
18624 enc_SetEnum(parent,command_fast_enc_pmap); ret = true; break;
18625 }
18626 }
18627 break;
18628 }
18629 case 6: {
18630 switch (u64(algo::ReadLE32(rhs.elems))|(u64(algo::ReadLE16(rhs.elems+4))<<32)) {
18631 case LE_STR6('s','c','a','l','e','d'): {
18632 enc_SetEnum(parent,command_fast_enc_scaled); ret = true; break;
18633 }
18634 case LE_STR6('s','i','g','n','e','d'): {
18635 enc_SetEnum(parent,command_fast_enc_signed); ret = true; break;
18636 }
18637 case LE_STR6('s','t','r','i','n','g'): {
18638 enc_SetEnum(parent,command_fast_enc_string); ret = true; break;
18639 }
18640 }
18641 break;
18642 }
18643 case 8: {
18644 switch (algo::ReadLE64(rhs.elems)) {
18645 case LE_STR8('u','n','s','i','g','n','e','d'): {
18646 enc_SetEnum(parent,command_fast_enc_unsigned); ret = true; break;
18647 }
18648 }
18649 break;
18650 }
18651 case 10: {
18652 switch (algo::ReadLE64(rhs.elems)) {
18653 case LE_STR8('b','y','t','e','v','e','c','t'): {
18654 if (memcmp(rhs.elems+8,"or",2)==0) { enc_SetEnum(parent,command_fast_enc_bytevector); ret = true; break; }
18655 break;
18656 }
18657 }
18658 break;
18659 }
18660 }
18661 return ret;
18662}
18663
18664// --- command.fast.enc.SetStrptr
18665// Convert string to field.
18666// If the string is invalid, set numeric value to DFLT
18667void command::enc_SetStrptr(command::fast& parent, algo::strptr rhs, command_fast_enc_Enum dflt) {
18668 if (!enc_SetStrptrMaybe(parent,rhs)) enc_SetEnum(parent,dflt);
18669}
18670
18671// --- command.fast.enc.ReadStrptrMaybe
18672// Convert string to field. Return success value
18673bool command::enc_ReadStrptrMaybe(command::fast& parent, algo::strptr rhs) {
18674 bool retval = false;
18675 retval = enc_SetStrptrMaybe(parent,rhs); // try symbol conversion
18676 if (!retval) { // didn't work? try reading as underlying type
18677 retval = u8_ReadStrptrMaybe(parent.enc,rhs);
18678 }
18679 return retval;
18680}
18681
18682// --- command.fast.ifmt.ToCstr
18683// Convert numeric value of field to one of predefined string constants.
18684// If string is found, return a static C string. Otherwise, return NULL.
18685const char* command::ifmt_ToCstr(const command::fast& parent) {
18686 const char *ret = NULL;
18687 switch(ifmt_GetEnum(parent)) {
18688 case command_fast_ifmt_none : ret = "none"; break;
18689 case command_fast_ifmt_fast : ret = "fast"; break;
18690 case command_fast_ifmt_ssim : ret = "ssim"; break;
18691 case command_fast_ifmt_xetradump : ret = "xetradump"; break;
18692 }
18693 return ret;
18694}
18695
18696// --- command.fast.ifmt.Print
18697// Convert ifmt to a string. First, attempt conversion to a known string.
18698// If no string matches, print ifmt as a numeric value.
18699void command::ifmt_Print(const command::fast& parent, algo::cstring &lhs) {
18700 const char *strval = ifmt_ToCstr(parent);
18701 if (strval) {
18702 lhs << strval;
18703 } else {
18704 lhs << parent.ifmt;
18705 }
18706}
18707
18708// --- command.fast.ifmt.SetStrptrMaybe
18709// Convert string to field.
18710// If the string is invalid, do not modify field and return false.
18711// In case of success, return true
18712bool command::ifmt_SetStrptrMaybe(command::fast& parent, algo::strptr rhs) {
18713 bool ret = false;
18714 switch (elems_N(rhs)) {
18715 case 4: {
18716 switch (u64(algo::ReadLE32(rhs.elems))) {
18717 case LE_STR4('f','a','s','t'): {
18718 ifmt_SetEnum(parent,command_fast_ifmt_fast); ret = true; break;
18719 }
18720 case LE_STR4('n','o','n','e'): {
18721 ifmt_SetEnum(parent,command_fast_ifmt_none); ret = true; break;
18722 }
18723 case LE_STR4('s','s','i','m'): {
18724 ifmt_SetEnum(parent,command_fast_ifmt_ssim); ret = true; break;
18725 }
18726 }
18727 break;
18728 }
18729 case 9: {
18730 switch (algo::ReadLE64(rhs.elems)) {
18731 case LE_STR8('x','e','t','r','a','d','u','m'): {
18732 if (memcmp(rhs.elems+8,"p",1)==0) { ifmt_SetEnum(parent,command_fast_ifmt_xetradump); ret = true; break; }
18733 break;
18734 }
18735 }
18736 break;
18737 }
18738 }
18739 return ret;
18740}
18741
18742// --- command.fast.ifmt.SetStrptr
18743// Convert string to field.
18744// If the string is invalid, set numeric value to DFLT
18745void command::ifmt_SetStrptr(command::fast& parent, algo::strptr rhs, command_fast_ifmt_Enum dflt) {
18746 if (!ifmt_SetStrptrMaybe(parent,rhs)) ifmt_SetEnum(parent,dflt);
18747}
18748
18749// --- command.fast.ifmt.ReadStrptrMaybe
18750// Convert string to field. Return success value
18751bool command::ifmt_ReadStrptrMaybe(command::fast& parent, algo::strptr rhs) {
18752 bool retval = false;
18753 retval = ifmt_SetStrptrMaybe(parent,rhs); // try symbol conversion
18754 if (!retval) { // didn't work? try reading as underlying type
18755 retval = u8_ReadStrptrMaybe(parent.ifmt,rhs);
18756 }
18757 return retval;
18758}
18759
18760// --- command.fast.ofmt.ToCstr
18761// Convert numeric value of field to one of predefined string constants.
18762// If string is found, return a static C string. Otherwise, return NULL.
18763const char* command::ofmt_ToCstr(const command::fast& parent) {
18764 const char *ret = NULL;
18765 switch(ofmt_GetEnum(parent)) {
18766 case command_fast_ofmt_none : ret = "none"; break;
18767 case command_fast_ofmt_fast : ret = "fast"; break;
18768 case command_fast_ofmt_ssim : ret = "ssim"; break;
18769 case command_fast_ofmt_tagvalue : ret = "tagvalue"; break;
18770 }
18771 return ret;
18772}
18773
18774// --- command.fast.ofmt.Print
18775// Convert ofmt to a string. First, attempt conversion to a known string.
18776// If no string matches, print ofmt as a numeric value.
18777void command::ofmt_Print(const command::fast& parent, algo::cstring &lhs) {
18778 const char *strval = ofmt_ToCstr(parent);
18779 if (strval) {
18780 lhs << strval;
18781 } else {
18782 lhs << parent.ofmt;
18783 }
18784}
18785
18786// --- command.fast.ofmt.SetStrptrMaybe
18787// Convert string to field.
18788// If the string is invalid, do not modify field and return false.
18789// In case of success, return true
18790bool command::ofmt_SetStrptrMaybe(command::fast& parent, algo::strptr rhs) {
18791 bool ret = false;
18792 switch (elems_N(rhs)) {
18793 case 4: {
18794 switch (u64(algo::ReadLE32(rhs.elems))) {
18795 case LE_STR4('f','a','s','t'): {
18796 ofmt_SetEnum(parent,command_fast_ofmt_fast); ret = true; break;
18797 }
18798 case LE_STR4('n','o','n','e'): {
18799 ofmt_SetEnum(parent,command_fast_ofmt_none); ret = true; break;
18800 }
18801 case LE_STR4('s','s','i','m'): {
18802 ofmt_SetEnum(parent,command_fast_ofmt_ssim); ret = true; break;
18803 }
18804 }
18805 break;
18806 }
18807 case 8: {
18808 switch (algo::ReadLE64(rhs.elems)) {
18809 case LE_STR8('t','a','g','v','a','l','u','e'): {
18810 ofmt_SetEnum(parent,command_fast_ofmt_tagvalue); ret = true; break;
18811 }
18812 }
18813 break;
18814 }
18815 }
18816 return ret;
18817}
18818
18819// --- command.fast.ofmt.SetStrptr
18820// Convert string to field.
18821// If the string is invalid, set numeric value to DFLT
18822void command::ofmt_SetStrptr(command::fast& parent, algo::strptr rhs, command_fast_ofmt_Enum dflt) {
18823 if (!ofmt_SetStrptrMaybe(parent,rhs)) ofmt_SetEnum(parent,dflt);
18824}
18825
18826// --- command.fast.ofmt.ReadStrptrMaybe
18827// Convert string to field. Return success value
18828bool command::ofmt_ReadStrptrMaybe(command::fast& parent, algo::strptr rhs) {
18829 bool retval = false;
18830 retval = ofmt_SetStrptrMaybe(parent,rhs); // try symbol conversion
18831 if (!retval) { // didn't work? try reading as underlying type
18832 retval = u8_ReadStrptrMaybe(parent.ofmt,rhs);
18833 }
18834 return retval;
18835}
18836
18837// --- command.fast..ReadFieldMaybe
18838bool command::fast_ReadFieldMaybe(command::fast& parent, algo::strptr field, algo::strptr strval) {
18839 bool retval = true;
18840 command::FieldId field_id;
18841 (void)value_SetStrptrMaybe(field_id,field);
18842 switch(field_id) {
18843 case command_FieldId_in: {
18844 retval = algo::cstring_ReadStrptrMaybe(parent.in, strval);
18845 break;
18846 }
18847 case command_FieldId_genamc: {
18848 retval = bool_ReadStrptrMaybe(parent.genamc, strval);
18849 break;
18850 }
18851 case command_FieldId_ns: {
18852 retval = algo::Smallstr16_ReadStrptrMaybe(parent.ns, strval);
18853 break;
18854 }
18855 case command_FieldId_xml: {
18856 retval = algo::cstring_ReadStrptrMaybe(parent.xml, strval);
18857 break;
18858 }
18859 case command_FieldId_add_reset: {
18860 retval = bool_ReadStrptrMaybe(parent.add_reset, strval);
18861 break;
18862 }
18863 case command_FieldId_pretty: {
18864 retval = bool_ReadStrptrMaybe(parent.pretty, strval);
18865 break;
18866 }
18867 case command_FieldId_write: {
18868 retval = bool_ReadStrptrMaybe(parent.write, strval);
18869 break;
18870 }
18871 case command_FieldId_encode: {
18872 retval = bool_ReadStrptrMaybe(parent.encode, strval);
18873 break;
18874 }
18875 case command_FieldId_decode: {
18876 retval = bool_ReadStrptrMaybe(parent.decode, strval);
18877 break;
18878 }
18879 case command_FieldId_enc: {
18880 retval = enc_ReadStrptrMaybe(parent, strval);
18881 break;
18882 }
18883 case command_FieldId_nullable: {
18884 retval = bool_ReadStrptrMaybe(parent.nullable, strval);
18885 break;
18886 }
18887 case command_FieldId_ifmt: {
18888 retval = ifmt_ReadStrptrMaybe(parent, strval);
18889 break;
18890 }
18891 case command_FieldId_ofmt: {
18892 retval = ofmt_ReadStrptrMaybe(parent, strval);
18893 break;
18894 }
18895 case command_FieldId_echo: {
18896 retval = bool_ReadStrptrMaybe(parent.echo, strval);
18897 break;
18898 }
18899 case command_FieldId_hex: {
18900 retval = bool_ReadStrptrMaybe(parent.hex, strval);
18901 break;
18902 }
18903 case command_FieldId_fix_bs: {
18904 retval = algo::Smallstr10_ReadStrptrMaybe(parent.fix_bs, strval);
18905 break;
18906 }
18907 case command_FieldId_fix_soh: {
18908 retval = char_ReadStrptrMaybe(parent.fix_soh, strval);
18909 break;
18910 }
18911 case command_FieldId_fix_nl: {
18912 retval = bool_ReadStrptrMaybe(parent.fix_nl, strval);
18913 break;
18914 }
18915 case command_FieldId_fast_msg_max: {
18916 retval = i32_ReadStrptrMaybe(parent.fast_msg_max, strval);
18917 break;
18918 }
18919 default: break;
18920 }
18921 if (!retval) {
18922 algo_lib::AppendErrtext("attr",field);
18923 }
18924 return retval;
18925}
18926
18927// --- command.fast..ReadTupleMaybe
18928// Read fields of command::fast from attributes of ascii tuple TUPLE
18929bool command::fast_ReadTupleMaybe(command::fast &parent, algo::Tuple &tuple) {
18930 bool retval = true;
18931 ind_beg(algo::Tuple_attrs_curs,attr,tuple) {
18932 retval = fast_ReadFieldMaybe(parent, attr.name, attr.value);
18933 if (!retval) {
18934 break;
18935 }
18936 }ind_end;
18937 return retval;
18938}
18939
18940// --- command.fast..Init
18941// Set all fields to initial values.
18942void command::fast_Init(command::fast& parent) {
18943 parent.in = algo::strptr("data");
18944 parent.genamc = bool(false);
18945 parent.ns = algo::strptr("");
18946 parent.xml = algo::strptr("");
18947 parent.add_reset = bool(true);
18948 parent.pretty = bool(false);
18949 parent.write = bool(false);
18950 parent.encode = bool(false);
18951 parent.decode = bool(false);
18952 parent.enc = u8(0);
18953 parent.nullable = bool(false);
18954 parent.ifmt = u8(0);
18955 parent.ofmt = u8(0);
18956 parent.echo = bool(false);
18957 parent.hex = bool(false);
18958 parent.fix_bs = algo::strptr("FIX.4.2");
18959 parent.fix_soh = char('|');
18960 parent.fix_nl = bool(true);
18961 parent.fast_msg_max = i32(1024);
18962}
18963
18964// --- command.fast..ToCmdline
18965// Convenience function that returns a full command line
18966// Assume command is in a directory called bin
18967tempstr command::fast_ToCmdline(command::fast& row) {
18968 tempstr ret;
18969 ret << "bin/fast ";
18970 fast_PrintArgv(row, ret);
18971 // inherit less intense verbose, debug options
18972 for (int i = 1; i < algo_lib::_db.cmdline.verbose; i++) {
18973 ret << " -verbose";
18974 }
18975 for (int i = 1; i < algo_lib::_db.cmdline.debug; i++) {
18976 ret << " -debug";
18977 }
18978 return ret;
18979}
18980
18981// --- command.fast..PrintArgv
18982// print string representation of ROW to string STR
18983// cfmt:command.fast.Argv printfmt:Tuple
18984void command::fast_PrintArgv(command::fast& row, algo::cstring& str) {
18985 algo::tempstr temp;
18986 (void)temp;
18987 (void)str;
18988 if (!(row.in == "data")) {
18989 ch_RemoveAll(temp);
18990 cstring_Print(row.in, temp);
18991 str << " -in:";
18992 strptr_PrintBash(temp,str);
18993 }
18994 if (!(row.genamc == false)) {
18995 ch_RemoveAll(temp);
18996 bool_Print(row.genamc, temp);
18997 str << " -genamc:";
18998 strptr_PrintBash(temp,str);
18999 }
19000 if (!(row.ns == "")) {
19001 ch_RemoveAll(temp);
19002 Smallstr16_Print(row.ns, temp);
19003 str << " -ns:";
19004 strptr_PrintBash(temp,str);
19005 }
19006 if (!(row.xml == "")) {
19007 ch_RemoveAll(temp);
19008 cstring_Print(row.xml, temp);
19009 str << " -xml:";
19010 strptr_PrintBash(temp,str);
19011 }
19012 if (!(row.add_reset == true)) {
19013 ch_RemoveAll(temp);
19014 bool_Print(row.add_reset, temp);
19015 str << " -add_reset:";
19016 strptr_PrintBash(temp,str);
19017 }
19018 if (!(row.pretty == false)) {
19019 ch_RemoveAll(temp);
19020 bool_Print(row.pretty, temp);
19021 str << " -pretty:";
19022 strptr_PrintBash(temp,str);
19023 }
19024 if (!(row.write == false)) {
19025 ch_RemoveAll(temp);
19026 bool_Print(row.write, temp);
19027 str << " -write:";
19028 strptr_PrintBash(temp,str);
19029 }
19030 if (!(row.encode == false)) {
19031 ch_RemoveAll(temp);
19032 bool_Print(row.encode, temp);
19033 str << " -encode:";
19034 strptr_PrintBash(temp,str);
19035 }
19036 if (!(row.decode == false)) {
19037 ch_RemoveAll(temp);
19038 bool_Print(row.decode, temp);
19039 str << " -decode:";
19040 strptr_PrintBash(temp,str);
19041 }
19042 if (!(row.enc == 0)) {
19043 ch_RemoveAll(temp);
19044 command::enc_Print(const_cast<command::fast&>(row), temp);
19045 str << " -enc:";
19046 strptr_PrintBash(temp,str);
19047 }
19048 if (!(row.nullable == false)) {
19049 ch_RemoveAll(temp);
19050 bool_Print(row.nullable, temp);
19051 str << " -nullable:";
19052 strptr_PrintBash(temp,str);
19053 }
19054 if (!(row.ifmt == 0)) {
19055 ch_RemoveAll(temp);
19056 command::ifmt_Print(const_cast<command::fast&>(row), temp);
19057 str << " -ifmt:";
19058 strptr_PrintBash(temp,str);
19059 }
19060 if (!(row.ofmt == 0)) {
19061 ch_RemoveAll(temp);
19062 command::ofmt_Print(const_cast<command::fast&>(row), temp);
19063 str << " -ofmt:";
19064 strptr_PrintBash(temp,str);
19065 }
19066 if (!(row.echo == false)) {
19067 ch_RemoveAll(temp);
19068 bool_Print(row.echo, temp);
19069 str << " -echo:";
19070 strptr_PrintBash(temp,str);
19071 }
19072 if (!(row.hex == false)) {
19073 ch_RemoveAll(temp);
19074 bool_Print(row.hex, temp);
19075 str << " -hex:";
19076 strptr_PrintBash(temp,str);
19077 }
19078 if (!(row.fix_bs == "FIX.4.2")) {
19079 ch_RemoveAll(temp);
19080 Smallstr10_Print(row.fix_bs, temp);
19081 str << " -fix_bs:";
19082 strptr_PrintBash(temp,str);
19083 }
19084 if (!(row.fix_soh == '|')) {
19085 ch_RemoveAll(temp);
19086 char_Print(row.fix_soh, temp);
19087 str << " -fix_soh:";
19088 strptr_PrintBash(temp,str);
19089 }
19090 if (!(row.fix_nl == true)) {
19091 ch_RemoveAll(temp);
19092 bool_Print(row.fix_nl, temp);
19093 str << " -fix_nl:";
19094 strptr_PrintBash(temp,str);
19095 }
19096 if (!(row.fast_msg_max == 1024)) {
19097 ch_RemoveAll(temp);
19098 i32_Print(row.fast_msg_max, temp);
19099 str << " -fast_msg_max:";
19100 strptr_PrintBash(temp,str);
19101 }
19102}
19103
19104// --- command.fast..NArgs
19105// Used with command lines
19106// Return # of command-line arguments that must follow this argument
19107// If FIELD is invalid, return -1
19108i32 command::fast_NArgs(command::FieldId field, algo::strptr& out_dflt, bool* out_anon) {
19109 i32 retval = 1;
19110 switch (field) {
19111 case command_FieldId_in: { // $comment
19112 *out_anon = false;
19113 } break;
19114 case command_FieldId_genamc: { // $comment
19115 *out_anon = false;
19116 retval=0;
19117 out_dflt="Y";
19118 } break;
19119 case command_FieldId_ns: { // bool: no argument required but value may be specified as genamc:Y
19120 *out_anon = false;
19121 } break;
19122 case command_FieldId_xml: { // bool: no argument required but value may be specified as genamc:Y
19123 *out_anon = false;
19124 } break;
19125 case command_FieldId_add_reset: { // bool: no argument required but value may be specified as genamc:Y
19126 *out_anon = false;
19127 retval=0;
19128 out_dflt="Y";
19129 } break;
19130 case command_FieldId_pretty: { // bool: no argument required but value may be specified as add_reset:Y
19131 *out_anon = false;
19132 retval=0;
19133 out_dflt="Y";
19134 } break;
19135 case command_FieldId_write: { // bool: no argument required but value may be specified as pretty:Y
19136 *out_anon = false;
19137 retval=0;
19138 out_dflt="Y";
19139 } break;
19140 case command_FieldId_encode: { // bool: no argument required but value may be specified as write:Y
19141 *out_anon = false;
19142 retval=0;
19143 out_dflt="Y";
19144 } break;
19145 case command_FieldId_decode: { // bool: no argument required but value may be specified as encode:Y
19146 *out_anon = false;
19147 retval=0;
19148 out_dflt="Y";
19149 } break;
19150 case command_FieldId_enc: { // bool: no argument required but value may be specified as decode:Y
19151 *out_anon = false;
19152 } break;
19153 case command_FieldId_nullable: { // bool: no argument required but value may be specified as decode:Y
19154 *out_anon = false;
19155 retval=0;
19156 out_dflt="Y";
19157 } break;
19158 case command_FieldId_ifmt: { // bool: no argument required but value may be specified as nullable:Y
19159 *out_anon = false;
19160 } break;
19161 case command_FieldId_ofmt: { // bool: no argument required but value may be specified as nullable:Y
19162 *out_anon = false;
19163 } break;
19164 case command_FieldId_echo: { // bool: no argument required but value may be specified as nullable:Y
19165 *out_anon = false;
19166 retval=0;
19167 out_dflt="Y";
19168 } break;
19169 case command_FieldId_hex: { // bool: no argument required but value may be specified as echo:Y
19170 *out_anon = false;
19171 retval=0;
19172 out_dflt="Y";
19173 } break;
19174 case command_FieldId_fix_bs: { // bool: no argument required but value may be specified as hex:Y
19175 *out_anon = false;
19176 } break;
19177 case command_FieldId_fix_soh: { // bool: no argument required but value may be specified as hex:Y
19178 *out_anon = false;
19179 } break;
19180 case command_FieldId_fix_nl: { // bool: no argument required but value may be specified as hex:Y
19181 *out_anon = false;
19182 retval=0;
19183 out_dflt="Y";
19184 } break;
19185 case command_FieldId_fast_msg_max: { // bool: no argument required but value may be specified as fix_nl:Y
19186 *out_anon = false;
19187 } break;
19188 default:
19189 retval=-1; // unrecognized
19190 }
19191 return retval;
19192}
19193
19194// --- command.fast_proc.fast.Start
19195// Start subprocess
19196// If subprocess already running, do nothing. Otherwise, start it
19197int command::fast_Start(command::fast_proc& parent) {
19198 int retval = 0;
19199 if (parent.pid == 0) {
19200 verblog(fast_ToCmdline(parent)); // maybe print command
19201#ifdef WIN32
19202 algo_lib::ResolveExecFname(parent.path);
19203 tempstr cmdline(fast_ToCmdline(parent));
19204 parent.pid = dospawn(Zeroterm(parent.path),Zeroterm(cmdline),parent.timeout,parent.fstdin,parent.fstdout,parent.fstderr);
19205#else
19206 parent.pid = fork();
19207 if (parent.pid == 0) { // child
19208 algo_lib::DieWithParent();
19209 if (parent.timeout > 0) {
19210 alarm(parent.timeout);
19211 }
19212 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstdin , 0);
19213 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstdout, 1);
19214 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstderr, 2);
19215 if (retval==0) retval= fast_Execv(parent);
19216 if (retval != 0) { // if start fails, print error
19217 int err=errno;
19218 prerr("command.fast_execv"
19219 <<Keyval("errno",err)
19220 <<Keyval("errstr",strerror(err))
19221 <<Keyval("comment","Execv failed"));
19222 }
19223 _exit(127); // if failed to start, exit anyway
19224 } else if (parent.pid == -1) {
19225 retval = errno; // failed to fork
19226 }
19227#endif
19228 }
19229 parent.status = parent.pid > 0 ? 0 : -1; // if didn't start, set error status
19230 return retval;
19231}
19232
19233// --- command.fast_proc.fast.StartRead
19234// Start subprocess & Read output
19235algo::Fildes command::fast_StartRead(command::fast_proc& parent, algo_lib::FFildes &read) {
19236 int pipefd[2];
19237 int rc=pipe(pipefd);
19238 (void)rc;
19239 read.fd.value = pipefd[0];
19240 parent.fstdout << ">&" << pipefd[1];
19241 fast_Start(parent);
19242 (void)close(pipefd[1]);
19243 return read.fd;
19244}
19245
19246// --- command.fast_proc.fast.Kill
19247// Kill subprocess and wait
19248void command::fast_Kill(command::fast_proc& parent) {
19249 if (parent.pid != 0) {
19250 kill(parent.pid,9);
19251 fast_Wait(parent);
19252 }
19253}
19254
19255// --- command.fast_proc.fast.Wait
19256// Wait for subprocess to return
19257void command::fast_Wait(command::fast_proc& parent) {
19258 if (parent.pid > 0) {
19259 int wait_flags = 0;
19260 int wait_status = 0;
19261 int rc = -1;
19262 do {
19263 // really wait for subprocess to exit
19264 rc = waitpid(parent.pid,&wait_status,wait_flags);
19265 } while (rc==-1 && errno==EINTR);
19266 if (rc == parent.pid) {
19267 parent.status = wait_status;
19268 parent.pid = 0;
19269 }
19270 }
19271}
19272
19273// --- command.fast_proc.fast.Exec
19274// Start + Wait
19275// Execute subprocess and return exit code
19276int command::fast_Exec(command::fast_proc& parent) {
19277 fast_Start(parent);
19278 fast_Wait(parent);
19279 return parent.status;
19280}
19281
19282// --- command.fast_proc.fast.ExecX
19283// Start + Wait, throw exception on error
19284// Execute subprocess; throw human-readable exception on error
19285void command::fast_ExecX(command::fast_proc& parent) {
19286 int rc = fast_Exec(parent);
19287 vrfy(rc==0, tempstr() << "algo_lib.exec" << Keyval("cmd",fast_ToCmdline(parent))
19288 << Keyval("comment",algo::DescribeWaitStatus(parent.status)));
19289}
19290
19291// --- command.fast_proc.fast.Execv
19292// Call execv()
19293// Call execv with specified parameters
19294int command::fast_Execv(command::fast_proc& parent) {
19295 int ret = 0;
19296 algo::StringAry args;
19297 fast_ToArgv(parent, args);
19298 char **argv = (char**)alloca((ary_N(args)+1)*sizeof(*argv));
19299 ind_beg(algo::StringAry_ary_curs,arg,args) {
19300 argv[ind_curs(arg).index] = Zeroterm(arg);
19301 }ind_end;
19302 argv[ary_N(args)] = NULL;
19303 // if parent.path is relative, search for it in PATH
19304 algo_lib::ResolveExecFname(parent.path);
19305 ret = execv(Zeroterm(parent.path),argv);
19306 return ret;
19307}
19308
19309// --- command.fast_proc.fast.ToCmdline
19310algo::tempstr command::fast_ToCmdline(command::fast_proc& parent) {
19311 algo::tempstr retval;
19312 retval << parent.path << " ";
19313 command::fast_PrintArgv(parent.cmd,retval);
19314 if (ch_N(parent.fstdin)) {
19315 retval << " " << parent.fstdin;
19316 }
19317 if (ch_N(parent.fstdout)) {
19318 retval << " " << parent.fstdout;
19319 }
19320 if (ch_N(parent.fstderr)) {
19321 retval << " 2" << parent.fstderr;
19322 }
19323 return retval;
19324}
19325
19326// --- command.fast_proc.fast.ToArgv
19327// Form array from the command line
19328void command::fast_ToArgv(command::fast_proc& parent, algo::StringAry& args) {
19329 ary_RemoveAll(args);
19330 ary_Alloc(args) << parent.path;
19331
19332 if (parent.cmd.in != "data") {
19333 cstring *arg = &ary_Alloc(args);
19334 *arg << "-in:";
19335 cstring_Print(parent.cmd.in, *arg);
19336 }
19337
19338 if (parent.cmd.genamc != false) {
19339 cstring *arg = &ary_Alloc(args);
19340 *arg << "-genamc:";
19341 bool_Print(parent.cmd.genamc, *arg);
19342 }
19343
19344 if (parent.cmd.ns != "") {
19345 cstring *arg = &ary_Alloc(args);
19346 *arg << "-ns:";
19347 Smallstr16_Print(parent.cmd.ns, *arg);
19348 }
19349
19350 if (parent.cmd.xml != "") {
19351 cstring *arg = &ary_Alloc(args);
19352 *arg << "-xml:";
19353 cstring_Print(parent.cmd.xml, *arg);
19354 }
19355
19356 if (parent.cmd.add_reset != true) {
19357 cstring *arg = &ary_Alloc(args);
19358 *arg << "-add_reset:";
19359 bool_Print(parent.cmd.add_reset, *arg);
19360 }
19361
19362 if (parent.cmd.pretty != false) {
19363 cstring *arg = &ary_Alloc(args);
19364 *arg << "-pretty:";
19365 bool_Print(parent.cmd.pretty, *arg);
19366 }
19367
19368 if (parent.cmd.write != false) {
19369 cstring *arg = &ary_Alloc(args);
19370 *arg << "-write:";
19371 bool_Print(parent.cmd.write, *arg);
19372 }
19373
19374 if (parent.cmd.encode != false) {
19375 cstring *arg = &ary_Alloc(args);
19376 *arg << "-encode:";
19377 bool_Print(parent.cmd.encode, *arg);
19378 }
19379
19380 if (parent.cmd.decode != false) {
19381 cstring *arg = &ary_Alloc(args);
19382 *arg << "-decode:";
19383 bool_Print(parent.cmd.decode, *arg);
19384 }
19385
19386 if (parent.cmd.enc != 0) {
19387 cstring *arg = &ary_Alloc(args);
19388 *arg << "-enc:";
19389 command::enc_Print(parent.cmd, *arg);
19390 }
19391
19392 if (parent.cmd.nullable != false) {
19393 cstring *arg = &ary_Alloc(args);
19394 *arg << "-nullable:";
19395 bool_Print(parent.cmd.nullable, *arg);
19396 }
19397
19398 if (parent.cmd.ifmt != 0) {
19399 cstring *arg = &ary_Alloc(args);
19400 *arg << "-ifmt:";
19401 command::ifmt_Print(parent.cmd, *arg);
19402 }
19403
19404 if (parent.cmd.ofmt != 0) {
19405 cstring *arg = &ary_Alloc(args);
19406 *arg << "-ofmt:";
19407 command::ofmt_Print(parent.cmd, *arg);
19408 }
19409
19410 if (parent.cmd.echo != false) {
19411 cstring *arg = &ary_Alloc(args);
19412 *arg << "-echo:";
19413 bool_Print(parent.cmd.echo, *arg);
19414 }
19415
19416 if (parent.cmd.hex != false) {
19417 cstring *arg = &ary_Alloc(args);
19418 *arg << "-hex:";
19419 bool_Print(parent.cmd.hex, *arg);
19420 }
19421
19422 if (parent.cmd.fix_bs != "FIX.4.2") {
19423 cstring *arg = &ary_Alloc(args);
19424 *arg << "-fix_bs:";
19425 Smallstr10_Print(parent.cmd.fix_bs, *arg);
19426 }
19427
19428 if (parent.cmd.fix_soh != '|') {
19429 cstring *arg = &ary_Alloc(args);
19430 *arg << "-fix_soh:";
19431 char_Print(parent.cmd.fix_soh, *arg);
19432 }
19433
19434 if (parent.cmd.fix_nl != true) {
19435 cstring *arg = &ary_Alloc(args);
19436 *arg << "-fix_nl:";
19437 bool_Print(parent.cmd.fix_nl, *arg);
19438 }
19439
19440 if (parent.cmd.fast_msg_max != 1024) {
19441 cstring *arg = &ary_Alloc(args);
19442 *arg << "-fast_msg_max:";
19443 i32_Print(parent.cmd.fast_msg_max, *arg);
19444 }
19445 for (int i=1; i < algo_lib::_db.cmdline.verbose; ++i) {
19446 ary_Alloc(args) << "-verbose";
19447 }
19448}
19449
19450// --- command.fast_proc..Uninit
19451void command::fast_proc_Uninit(command::fast_proc& parent) {
19452 command::fast_proc &row = parent; (void)row;
19453
19454 // command.fast_proc.fast.Uninit (Exec) //
19455 fast_Kill(parent); // kill child, ensure forward progress
19456}
19457
19458// --- command.gcache.cmd.Addary
19459// Reserve space (this may move memory). Insert N element at the end.
19460// Return aryptr to newly inserted block.
19461// If the RHS argument aliases the array (refers to the same memory), exit program with fatal error.
19462algo::aryptr<algo::cstring> command::cmd_Addary(command::gcache& parent, algo::aryptr<algo::cstring> rhs) {
19463 bool overlaps = rhs.n_elems>0 && rhs.elems >= parent.cmd_elems && rhs.elems < parent.cmd_elems + parent.cmd_max;
19464 if (UNLIKELY(overlaps)) {
19465 FatalErrorExit("command.tary_alias field:command.gcache.cmd comment:'alias error: sub-array is being appended to the whole'");
19466 }
19467 int nnew = rhs.n_elems;
19468 cmd_Reserve(parent, nnew); // reserve space
19469 int at = parent.cmd_n;
19470 for (int i = 0; i < nnew; i++) {
19471 new (parent.cmd_elems + at + i) algo::cstring(rhs[i]);
19472 parent.cmd_n++;
19473 }
19474 return algo::aryptr<algo::cstring>(parent.cmd_elems + at, nnew);
19475}
19476
19477// --- command.gcache.cmd.Alloc
19478// Reserve space. Insert element at the end
19479// The new element is initialized to a default value
19480algo::cstring& command::cmd_Alloc(command::gcache& parent) {
19481 cmd_Reserve(parent, 1);
19482 int n = parent.cmd_n;
19483 int at = n;
19484 algo::cstring *elems = parent.cmd_elems;
19485 new (elems + at) algo::cstring(); // construct new element, default initializer
19486 parent.cmd_n = n+1;
19487 return elems[at];
19488}
19489
19490// --- command.gcache.cmd.AllocAt
19491// Reserve space for new element, reallocating the array if necessary
19492// Insert new element at specified index. Index must be in range or a fatal error occurs.
19493algo::cstring& command::cmd_AllocAt(command::gcache& parent, int at) {
19494 cmd_Reserve(parent, 1);
19495 int n = parent.cmd_n;
19496 if (UNLIKELY(u64(at) >= u64(n+1))) {
19497 FatalErrorExit("command.bad_alloc_at field:command.gcache.cmd comment:'index out of range'");
19498 }
19499 algo::cstring *elems = parent.cmd_elems;
19500 memmove(elems + at + 1, elems + at, (n - at) * sizeof(algo::cstring));
19501 new (elems + at) algo::cstring(); // construct element, default initializer
19502 parent.cmd_n = n+1;
19503 return elems[at];
19504}
19505
19506// --- command.gcache.cmd.AllocN
19507// Reserve space. Insert N elements at the end of the array, return pointer to array
19508algo::aryptr<algo::cstring> command::cmd_AllocN(command::gcache& parent, int n_elems) {
19509 cmd_Reserve(parent, n_elems);
19510 int old_n = parent.cmd_n;
19511 int new_n = old_n + n_elems;
19512 algo::cstring *elems = parent.cmd_elems;
19513 for (int i = old_n; i < new_n; i++) {
19514 new (elems + i) algo::cstring(); // construct new element, default initialize
19515 }
19516 parent.cmd_n = new_n;
19517 return algo::aryptr<algo::cstring>(elems + old_n, n_elems);
19518}
19519
19520// --- command.gcache.cmd.Remove
19521// Remove item by index. If index outside of range, do nothing.
19522void command::cmd_Remove(command::gcache& parent, u32 i) {
19523 u32 lim = parent.cmd_n;
19524 algo::cstring *elems = parent.cmd_elems;
19525 if (i < lim) {
19526 elems[i].~cstring(); // destroy element
19527 memmove(elems + i, elems + (i + 1), sizeof(algo::cstring) * (lim - (i + 1)));
19528 parent.cmd_n = lim - 1;
19529 }
19530}
19531
19532// --- command.gcache.cmd.RemoveAll
19533void command::cmd_RemoveAll(command::gcache& parent) {
19534 u32 n = parent.cmd_n;
19535 while (n > 0) {
19536 n -= 1;
19537 parent.cmd_elems[n].~cstring();
19538 parent.cmd_n = n;
19539 }
19540}
19541
19542// --- command.gcache.cmd.RemoveLast
19543// Delete last element of array. Do nothing if array is empty.
19544void command::cmd_RemoveLast(command::gcache& parent) {
19545 u64 n = parent.cmd_n;
19546 if (n > 0) {
19547 n -= 1;
19548 cmd_qFind(parent, u64(n)).~cstring();
19549 parent.cmd_n = n;
19550 }
19551}
19552
19553// --- command.gcache.cmd.AbsReserve
19554// Make sure N elements fit in array. Process dies if out of memory
19555void command::cmd_AbsReserve(command::gcache& parent, int n) {
19556 u32 old_max = parent.cmd_max;
19557 if (n > i32(old_max)) {
19558 u32 new_max = i32_Max(i32_Max(old_max * 2, n), 4);
19559 void *new_mem = algo_lib::malloc_ReallocMem(parent.cmd_elems, old_max * sizeof(algo::cstring), new_max * sizeof(algo::cstring));
19560 if (UNLIKELY(!new_mem)) {
19561 FatalErrorExit("command.tary_nomem field:command.gcache.cmd comment:'out of memory'");
19562 }
19563 parent.cmd_elems = (algo::cstring*)new_mem;
19564 parent.cmd_max = new_max;
19565 }
19566}
19567
19568// --- command.gcache.cmd.Setary
19569// Copy contents of RHS to PARENT.
19570void command::cmd_Setary(command::gcache& parent, command::gcache &rhs) {
19571 cmd_RemoveAll(parent);
19572 int nnew = rhs.cmd_n;
19573 cmd_Reserve(parent, nnew); // reserve space
19574 for (int i = 0; i < nnew; i++) { // copy elements over
19575 new (parent.cmd_elems + i) algo::cstring(cmd_qFind(rhs, i));
19576 parent.cmd_n = i + 1;
19577 }
19578}
19579
19580// --- command.gcache.cmd.Setary2
19581// Copy specified array into cmd, discarding previous contents.
19582// If the RHS argument aliases the array (refers to the same memory), throw exception.
19583void command::cmd_Setary(command::gcache& parent, const algo::aryptr<algo::cstring> &rhs) {
19584 cmd_RemoveAll(parent);
19585 cmd_Addary(parent, rhs);
19586}
19587
19588// --- command.gcache.cmd.AllocNVal
19589// Reserve space. Insert N elements at the end of the array, return pointer to array
19590algo::aryptr<algo::cstring> command::cmd_AllocNVal(command::gcache& parent, int n_elems, const algo::cstring& val) {
19591 cmd_Reserve(parent, n_elems);
19592 int old_n = parent.cmd_n;
19593 int new_n = old_n + n_elems;
19594 algo::cstring *elems = parent.cmd_elems;
19595 for (int i = old_n; i < new_n; i++) {
19596 new (elems + i) algo::cstring(val);
19597 }
19598 parent.cmd_n = new_n;
19599 return algo::aryptr<algo::cstring>(elems + old_n, n_elems);
19600}
19601
19602// --- command.gcache.cmd.ReadStrptrMaybe
19603// A single element is read from input string and appended to the array.
19604// If the string contains an error, the array is untouched.
19605// Function returns success value.
19606bool command::cmd_ReadStrptrMaybe(command::gcache& parent, algo::strptr in_str) {
19607 bool retval = true;
19608 algo::cstring &elem = cmd_Alloc(parent);
19609 retval = algo::cstring_ReadStrptrMaybe(elem, in_str);
19610 if (!retval) {
19611 cmd_RemoveLast(parent);
19612 }
19613 return retval;
19614}
19615
19616// --- command.gcache..ReadFieldMaybe
19617bool command::gcache_ReadFieldMaybe(command::gcache& parent, algo::strptr field, algo::strptr strval) {
19618 bool retval = true;
19619 command::FieldId field_id;
19620 (void)value_SetStrptrMaybe(field_id,algo::Pathcomp(field, ".LL"));
19621 switch(field_id) {
19622 case command_FieldId_in: {
19623 retval = algo::cstring_ReadStrptrMaybe(parent.in, strval);
19624 break;
19625 }
19626 case command_FieldId_cmd: {
19627 retval = cmd_ReadStrptrMaybe(parent, strval);
19628 break;
19629 }
19630 case command_FieldId_install: {
19631 retval = bool_ReadStrptrMaybe(parent.install, strval);
19632 break;
19633 }
19634 case command_FieldId_stats: {
19635 retval = bool_ReadStrptrMaybe(parent.stats, strval);
19636 break;
19637 }
19638 case command_FieldId_enable: {
19639 retval = bool_ReadStrptrMaybe(parent.enable, strval);
19640 break;
19641 }
19642 case command_FieldId_disable: {
19643 retval = bool_ReadStrptrMaybe(parent.disable, strval);
19644 break;
19645 }
19646 case command_FieldId_gc: {
19647 retval = bool_ReadStrptrMaybe(parent.gc, strval);
19648 break;
19649 }
19650 case command_FieldId_clean: {
19651 retval = bool_ReadStrptrMaybe(parent.clean, strval);
19652 break;
19653 }
19654 case command_FieldId_dir: {
19655 retval = algo::cstring_ReadStrptrMaybe(parent.dir, strval);
19656 break;
19657 }
19658 case command_FieldId_hitrate: {
19659 retval = bool_ReadStrptrMaybe(parent.hitrate, strval);
19660 break;
19661 }
19662 case command_FieldId_after: {
19663 retval = algo::UnTime_ReadStrptrMaybe(parent.after, strval);
19664 break;
19665 }
19666 case command_FieldId_report: {
19667 retval = bool_ReadStrptrMaybe(parent.report, strval);
19668 break;
19669 }
19670 case command_FieldId_force: {
19671 retval = bool_ReadStrptrMaybe(parent.force, strval);
19672 break;
19673 }
19674 default: break;
19675 }
19676 if (!retval) {
19677 algo_lib::AppendErrtext("attr",field);
19678 }
19679 return retval;
19680}
19681
19682// --- command.gcache..ReadTupleMaybe
19683// Read fields of command::gcache from attributes of ascii tuple TUPLE
19684bool command::gcache_ReadTupleMaybe(command::gcache &parent, algo::Tuple &tuple) {
19685 bool retval = true;
19686 int anon_idx = 0;
19687 ind_beg(algo::Tuple_attrs_curs,attr,tuple) {
19688 if (ch_N(attr.name) == 0) {
19689 attr.name = gcache_GetAnon(parent, anon_idx++);
19690 }
19691 retval = gcache_ReadFieldMaybe(parent, attr.name, attr.value);
19692 if (!retval) {
19693 break;
19694 }
19695 }ind_end;
19696 return retval;
19697}
19698
19699// --- command.gcache..Init
19700// Set all fields to initial values.
19701void command::gcache_Init(command::gcache& parent) {
19702 parent.in = algo::strptr("data");
19703 parent.cmd_elems = 0; // (command.gcache.cmd)
19704 parent.cmd_n = 0; // (command.gcache.cmd)
19705 parent.cmd_max = 0; // (command.gcache.cmd)
19706 parent.install = bool(false);
19707 parent.stats = bool(false);
19708 parent.enable = bool(false);
19709 parent.disable = bool(false);
19710 parent.gc = bool(false);
19711 parent.clean = bool(false);
19712 parent.dir = algo::strptr("/tmp/gcache");
19713 parent.hitrate = bool(false);
19714 parent.report = bool(false);
19715 parent.force = bool(false);
19716}
19717
19718// --- command.gcache..Uninit
19719void command::gcache_Uninit(command::gcache& parent) {
19720 command::gcache &row = parent; (void)row;
19721
19722 // command.gcache.cmd.Uninit (Tary) //Command to execute
19723 // remove all elements from command.gcache.cmd
19724 cmd_RemoveAll(parent);
19725 // free memory for Tary command.gcache.cmd
19726 algo_lib::malloc_FreeMem(parent.cmd_elems, sizeof(algo::cstring)*parent.cmd_max); // (command.gcache.cmd)
19727}
19728
19729// --- command.gcache..ToCmdline
19730// Convenience function that returns a full command line
19731// Assume command is in a directory called bin
19732tempstr command::gcache_ToCmdline(command::gcache& row) {
19733 tempstr ret;
19734 ret << "bin/gcache ";
19735 gcache_PrintArgv(row, ret);
19736 // inherit less intense verbose, debug options
19737 for (int i = 1; i < algo_lib::_db.cmdline.verbose; i++) {
19738 ret << " -verbose";
19739 }
19740 for (int i = 1; i < algo_lib::_db.cmdline.debug; i++) {
19741 ret << " -debug";
19742 }
19743 return ret;
19744}
19745
19746// --- command.gcache..PrintArgv
19747// print string representation of ROW to string STR
19748// cfmt:command.gcache.Argv printfmt:Tuple
19749void command::gcache_PrintArgv(command::gcache& row, algo::cstring& str) {
19750 algo::tempstr temp;
19751 (void)temp;
19752 (void)str;
19753 if (!(row.in == "data")) {
19754 ch_RemoveAll(temp);
19755 cstring_Print(row.in, temp);
19756 str << " -in:";
19757 strptr_PrintBash(temp,str);
19758 }
19759 ind_beg(gcache_cmd_curs,value,row) {
19760 ch_RemoveAll(temp);
19761 cstring_Print(value, temp);
19762 str << " -cmd:";
19763 strptr_PrintBash(temp,str);
19764 }ind_end;
19765 if (!(row.install == false)) {
19766 ch_RemoveAll(temp);
19767 bool_Print(row.install, temp);
19768 str << " -install:";
19769 strptr_PrintBash(temp,str);
19770 }
19771 if (!(row.stats == false)) {
19772 ch_RemoveAll(temp);
19773 bool_Print(row.stats, temp);
19774 str << " -stats:";
19775 strptr_PrintBash(temp,str);
19776 }
19777 if (!(row.enable == false)) {
19778 ch_RemoveAll(temp);
19779 bool_Print(row.enable, temp);
19780 str << " -enable:";
19781 strptr_PrintBash(temp,str);
19782 }
19783 if (!(row.disable == false)) {
19784 ch_RemoveAll(temp);
19785 bool_Print(row.disable, temp);
19786 str << " -disable:";
19787 strptr_PrintBash(temp,str);
19788 }
19789 if (!(row.gc == false)) {
19790 ch_RemoveAll(temp);
19791 bool_Print(row.gc, temp);
19792 str << " -gc:";
19793 strptr_PrintBash(temp,str);
19794 }
19795 if (!(row.clean == false)) {
19796 ch_RemoveAll(temp);
19797 bool_Print(row.clean, temp);
19798 str << " -clean:";
19799 strptr_PrintBash(temp,str);
19800 }
19801 if (!(row.dir == "/tmp/gcache")) {
19802 ch_RemoveAll(temp);
19803 cstring_Print(row.dir, temp);
19804 str << " -dir:";
19805 strptr_PrintBash(temp,str);
19806 }
19807 if (!(row.hitrate == false)) {
19808 ch_RemoveAll(temp);
19809 bool_Print(row.hitrate, temp);
19810 str << " -hitrate:";
19811 strptr_PrintBash(temp,str);
19812 }
19813 if (!(UnTime_Eq(row.after, algo::UnTime()))) {
19814 ch_RemoveAll(temp);
19815 UnTime_Print(row.after, temp);
19816 str << " -after:";
19817 strptr_PrintBash(temp,str);
19818 }
19819 if (!(row.report == false)) {
19820 ch_RemoveAll(temp);
19821 bool_Print(row.report, temp);
19822 str << " -report:";
19823 strptr_PrintBash(temp,str);
19824 }
19825 if (!(row.force == false)) {
19826 ch_RemoveAll(temp);
19827 bool_Print(row.force, temp);
19828 str << " -force:";
19829 strptr_PrintBash(temp,str);
19830 }
19831}
19832
19833// --- command.gcache..Print
19834// print string representation of ROW to string STR
19835// cfmt:command.gcache.String printfmt:Tuple
19836void command::gcache_Print(command::gcache& row, algo::cstring& str) {
19837 algo::tempstr temp;
19838 str << "command.gcache";
19839
19840 algo::cstring_Print(row.in, temp);
19841 PrintAttrSpaceReset(str,"in", temp);
19842
19843 ind_beg(gcache_cmd_curs,cmd,row) {
19844 algo::cstring_Print(cmd, temp);
19845 tempstr name;
19846 name << "cmd.";
19847 name << ind_curs(cmd).index;
19848 PrintAttrSpaceReset(str, name, temp);
19849 }ind_end;
19850
19851 bool_Print(row.install, temp);
19852 PrintAttrSpaceReset(str,"install", temp);
19853
19854 bool_Print(row.stats, temp);
19855 PrintAttrSpaceReset(str,"stats", temp);
19856
19857 bool_Print(row.enable, temp);
19858 PrintAttrSpaceReset(str,"enable", temp);
19859
19860 bool_Print(row.disable, temp);
19861 PrintAttrSpaceReset(str,"disable", temp);
19862
19863 bool_Print(row.gc, temp);
19864 PrintAttrSpaceReset(str,"gc", temp);
19865
19866 bool_Print(row.clean, temp);
19867 PrintAttrSpaceReset(str,"clean", temp);
19868
19869 algo::cstring_Print(row.dir, temp);
19870 PrintAttrSpaceReset(str,"dir", temp);
19871
19872 bool_Print(row.hitrate, temp);
19873 PrintAttrSpaceReset(str,"hitrate", temp);
19874
19875 algo::UnTime_Print(row.after, temp);
19876 PrintAttrSpaceReset(str,"after", temp);
19877
19878 bool_Print(row.report, temp);
19879 PrintAttrSpaceReset(str,"report", temp);
19880
19881 bool_Print(row.force, temp);
19882 PrintAttrSpaceReset(str,"force", temp);
19883}
19884
19885// --- command.gcache..GetAnon
19886algo::strptr command::gcache_GetAnon(command::gcache &parent, i32 idx) {
19887 (void)parent;//only to avoid -Wunused-parameter
19888 switch(idx) {
19889 default: return strptr("cmd", 3);
19890 }
19891}
19892
19893// --- command.gcache..NArgs
19894// Used with command lines
19895// Return # of command-line arguments that must follow this argument
19896// If FIELD is invalid, return -1
19897i32 command::gcache_NArgs(command::FieldId field, algo::strptr& out_dflt, bool* out_anon) {
19898 i32 retval = 1;
19899 switch (field) {
19900 case command_FieldId_in: { // $comment
19901 *out_anon = false;
19902 } break;
19903 case command_FieldId_cmd: { // $comment
19904 *out_anon = true;
19905 } break;
19906 case command_FieldId_install: { // $comment
19907 *out_anon = false;
19908 retval=0;
19909 out_dflt="Y";
19910 } break;
19911 case command_FieldId_stats: { // bool: no argument required but value may be specified as install:Y
19912 *out_anon = false;
19913 retval=0;
19914 out_dflt="Y";
19915 } break;
19916 case command_FieldId_enable: { // bool: no argument required but value may be specified as stats:Y
19917 *out_anon = false;
19918 retval=0;
19919 out_dflt="Y";
19920 } break;
19921 case command_FieldId_disable: { // bool: no argument required but value may be specified as enable:Y
19922 *out_anon = false;
19923 retval=0;
19924 out_dflt="Y";
19925 } break;
19926 case command_FieldId_gc: { // bool: no argument required but value may be specified as disable:Y
19927 *out_anon = false;
19928 retval=0;
19929 out_dflt="Y";
19930 } break;
19931 case command_FieldId_clean: { // bool: no argument required but value may be specified as gc:Y
19932 *out_anon = false;
19933 retval=0;
19934 out_dflt="Y";
19935 } break;
19936 case command_FieldId_dir: { // bool: no argument required but value may be specified as clean:Y
19937 *out_anon = false;
19938 } break;
19939 case command_FieldId_hitrate: { // bool: no argument required but value may be specified as clean:Y
19940 *out_anon = false;
19941 retval=0;
19942 out_dflt="Y";
19943 } break;
19944 case command_FieldId_after: { // bool: no argument required but value may be specified as hitrate:Y
19945 *out_anon = false;
19946 } break;
19947 case command_FieldId_report: { // bool: no argument required but value may be specified as hitrate:Y
19948 *out_anon = false;
19949 retval=0;
19950 out_dflt="Y";
19951 } break;
19952 case command_FieldId_force: { // bool: no argument required but value may be specified as report:Y
19953 *out_anon = false;
19954 retval=0;
19955 out_dflt="Y";
19956 } break;
19957 default:
19958 retval=-1; // unrecognized
19959 }
19960 return retval;
19961}
19962
19963// --- command.gcache_proc.gcache.Start
19964// Start subprocess
19965// If subprocess already running, do nothing. Otherwise, start it
19966int command::gcache_Start(command::gcache_proc& parent) {
19967 int retval = 0;
19968 if (parent.pid == 0) {
19969 verblog(gcache_ToCmdline(parent)); // maybe print command
19970#ifdef WIN32
19971 algo_lib::ResolveExecFname(parent.path);
19972 tempstr cmdline(gcache_ToCmdline(parent));
19973 parent.pid = dospawn(Zeroterm(parent.path),Zeroterm(cmdline),parent.timeout,parent.fstdin,parent.fstdout,parent.fstderr);
19974#else
19975 parent.pid = fork();
19976 if (parent.pid == 0) { // child
19977 algo_lib::DieWithParent();
19978 if (parent.timeout > 0) {
19979 alarm(parent.timeout);
19980 }
19981 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstdin , 0);
19982 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstdout, 1);
19983 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstderr, 2);
19984 if (retval==0) retval= gcache_Execv(parent);
19985 if (retval != 0) { // if start fails, print error
19986 int err=errno;
19987 prerr("command.gcache_execv"
19988 <<Keyval("errno",err)
19989 <<Keyval("errstr",strerror(err))
19990 <<Keyval("comment","Execv failed"));
19991 }
19992 _exit(127); // if failed to start, exit anyway
19993 } else if (parent.pid == -1) {
19994 retval = errno; // failed to fork
19995 }
19996#endif
19997 }
19998 parent.status = parent.pid > 0 ? 0 : -1; // if didn't start, set error status
19999 return retval;
20000}
20001
20002// --- command.gcache_proc.gcache.StartRead
20003// Start subprocess & Read output
20004algo::Fildes command::gcache_StartRead(command::gcache_proc& parent, algo_lib::FFildes &read) {
20005 int pipefd[2];
20006 int rc=pipe(pipefd);
20007 (void)rc;
20008 read.fd.value = pipefd[0];
20009 parent.fstdout << ">&" << pipefd[1];
20010 gcache_Start(parent);
20011 (void)close(pipefd[1]);
20012 return read.fd;
20013}
20014
20015// --- command.gcache_proc.gcache.Kill
20016// Kill subprocess and wait
20017void command::gcache_Kill(command::gcache_proc& parent) {
20018 if (parent.pid != 0) {
20019 kill(parent.pid,9);
20020 gcache_Wait(parent);
20021 }
20022}
20023
20024// --- command.gcache_proc.gcache.Wait
20025// Wait for subprocess to return
20026void command::gcache_Wait(command::gcache_proc& parent) {
20027 if (parent.pid > 0) {
20028 int wait_flags = 0;
20029 int wait_status = 0;
20030 int rc = -1;
20031 do {
20032 // really wait for subprocess to exit
20033 rc = waitpid(parent.pid,&wait_status,wait_flags);
20034 } while (rc==-1 && errno==EINTR);
20035 if (rc == parent.pid) {
20036 parent.status = wait_status;
20037 parent.pid = 0;
20038 }
20039 }
20040}
20041
20042// --- command.gcache_proc.gcache.Exec
20043// Start + Wait
20044// Execute subprocess and return exit code
20045int command::gcache_Exec(command::gcache_proc& parent) {
20046 gcache_Start(parent);
20047 gcache_Wait(parent);
20048 return parent.status;
20049}
20050
20051// --- command.gcache_proc.gcache.ExecX
20052// Start + Wait, throw exception on error
20053// Execute subprocess; throw human-readable exception on error
20054void command::gcache_ExecX(command::gcache_proc& parent) {
20055 int rc = gcache_Exec(parent);
20056 vrfy(rc==0, tempstr() << "algo_lib.exec" << Keyval("cmd",gcache_ToCmdline(parent))
20057 << Keyval("comment",algo::DescribeWaitStatus(parent.status)));
20058}
20059
20060// --- command.gcache_proc.gcache.Execv
20061// Call execv()
20062// Call execv with specified parameters
20063int command::gcache_Execv(command::gcache_proc& parent) {
20064 int ret = 0;
20065 algo::StringAry args;
20066 gcache_ToArgv(parent, args);
20067 char **argv = (char**)alloca((ary_N(args)+1)*sizeof(*argv));
20068 ind_beg(algo::StringAry_ary_curs,arg,args) {
20069 argv[ind_curs(arg).index] = Zeroterm(arg);
20070 }ind_end;
20071 argv[ary_N(args)] = NULL;
20072 // if parent.path is relative, search for it in PATH
20073 algo_lib::ResolveExecFname(parent.path);
20074 ret = execv(Zeroterm(parent.path),argv);
20075 return ret;
20076}
20077
20078// --- command.gcache_proc.gcache.ToCmdline
20079algo::tempstr command::gcache_ToCmdline(command::gcache_proc& parent) {
20080 algo::tempstr retval;
20081 retval << parent.path << " ";
20082 command::gcache_PrintArgv(parent.cmd,retval);
20083 if (ch_N(parent.fstdin)) {
20084 retval << " " << parent.fstdin;
20085 }
20086 if (ch_N(parent.fstdout)) {
20087 retval << " " << parent.fstdout;
20088 }
20089 if (ch_N(parent.fstderr)) {
20090 retval << " 2" << parent.fstderr;
20091 }
20092 return retval;
20093}
20094
20095// --- command.gcache_proc.gcache.ToArgv
20096// Form array from the command line
20097void command::gcache_ToArgv(command::gcache_proc& parent, algo::StringAry& args) {
20098 ary_RemoveAll(args);
20099 ary_Alloc(args) << parent.path;
20100
20101 if (parent.cmd.in != "data") {
20102 cstring *arg = &ary_Alloc(args);
20103 *arg << "-in:";
20104 cstring_Print(parent.cmd.in, *arg);
20105 }
20106 ind_beg(command::gcache_cmd_curs,value,parent.cmd) {
20107 cstring *arg = &ary_Alloc(args);
20108 *arg << "-cmd:";
20109 cstring_Print(value, *arg);
20110 }ind_end;
20111
20112 if (parent.cmd.install != false) {
20113 cstring *arg = &ary_Alloc(args);
20114 *arg << "-install:";
20115 bool_Print(parent.cmd.install, *arg);
20116 }
20117
20118 if (parent.cmd.stats != false) {
20119 cstring *arg = &ary_Alloc(args);
20120 *arg << "-stats:";
20121 bool_Print(parent.cmd.stats, *arg);
20122 }
20123
20124 if (parent.cmd.enable != false) {
20125 cstring *arg = &ary_Alloc(args);
20126 *arg << "-enable:";
20127 bool_Print(parent.cmd.enable, *arg);
20128 }
20129
20130 if (parent.cmd.disable != false) {
20131 cstring *arg = &ary_Alloc(args);
20132 *arg << "-disable:";
20133 bool_Print(parent.cmd.disable, *arg);
20134 }
20135
20136 if (parent.cmd.gc != false) {
20137 cstring *arg = &ary_Alloc(args);
20138 *arg << "-gc:";
20139 bool_Print(parent.cmd.gc, *arg);
20140 }
20141
20142 if (parent.cmd.clean != false) {
20143 cstring *arg = &ary_Alloc(args);
20144 *arg << "-clean:";
20145 bool_Print(parent.cmd.clean, *arg);
20146 }
20147
20148 if (parent.cmd.dir != "/tmp/gcache") {
20149 cstring *arg = &ary_Alloc(args);
20150 *arg << "-dir:";
20151 cstring_Print(parent.cmd.dir, *arg);
20152 }
20153
20154 if (parent.cmd.hitrate != false) {
20155 cstring *arg = &ary_Alloc(args);
20156 *arg << "-hitrate:";
20157 bool_Print(parent.cmd.hitrate, *arg);
20158 }
20159
20160 if (true) {
20161 cstring *arg = &ary_Alloc(args);
20162 *arg << "-after:";
20163 UnTime_Print(parent.cmd.after, *arg);
20164 }
20165
20166 if (parent.cmd.report != false) {
20167 cstring *arg = &ary_Alloc(args);
20168 *arg << "-report:";
20169 bool_Print(parent.cmd.report, *arg);
20170 }
20171
20172 if (parent.cmd.force != false) {
20173 cstring *arg = &ary_Alloc(args);
20174 *arg << "-force:";
20175 bool_Print(parent.cmd.force, *arg);
20176 }
20177 for (int i=1; i < algo_lib::_db.cmdline.verbose; ++i) {
20178 ary_Alloc(args) << "-verbose";
20179 }
20180}
20181
20182// --- command.gcache_proc..Uninit
20183void command::gcache_proc_Uninit(command::gcache_proc& parent) {
20184 command::gcache_proc &row = parent; (void)row;
20185
20186 // command.gcache_proc.gcache.Uninit (Exec) //
20187 gcache_Kill(parent); // kill child, ensure forward progress
20188}
20189
20190// --- command.gcli.fields.Addary
20191// Reserve space (this may move memory). Insert N element at the end.
20192// Return aryptr to newly inserted block.
20193// If the RHS argument aliases the array (refers to the same memory), exit program with fatal error.
20194algo::aryptr<algo::cstring> command::fields_Addary(command::gcli& parent, algo::aryptr<algo::cstring> rhs) {
20195 bool overlaps = rhs.n_elems>0 && rhs.elems >= parent.fields_elems && rhs.elems < parent.fields_elems + parent.fields_max;
20196 if (UNLIKELY(overlaps)) {
20197 FatalErrorExit("command.tary_alias field:command.gcli.fields comment:'alias error: sub-array is being appended to the whole'");
20198 }
20199 int nnew = rhs.n_elems;
20200 fields_Reserve(parent, nnew); // reserve space
20201 int at = parent.fields_n;
20202 for (int i = 0; i < nnew; i++) {
20203 new (parent.fields_elems + at + i) algo::cstring(rhs[i]);
20204 parent.fields_n++;
20205 }
20206 return algo::aryptr<algo::cstring>(parent.fields_elems + at, nnew);
20207}
20208
20209// --- command.gcli.fields.Alloc
20210// Reserve space. Insert element at the end
20211// The new element is initialized to a default value
20212algo::cstring& command::fields_Alloc(command::gcli& parent) {
20213 fields_Reserve(parent, 1);
20214 int n = parent.fields_n;
20215 int at = n;
20216 algo::cstring *elems = parent.fields_elems;
20217 new (elems + at) algo::cstring(""); // construct new element, default initializer
20218 parent.fields_n = n+1;
20219 return elems[at];
20220}
20221
20222// --- command.gcli.fields.AllocAt
20223// Reserve space for new element, reallocating the array if necessary
20224// Insert new element at specified index. Index must be in range or a fatal error occurs.
20225algo::cstring& command::fields_AllocAt(command::gcli& parent, int at) {
20226 fields_Reserve(parent, 1);
20227 int n = parent.fields_n;
20228 if (UNLIKELY(u64(at) >= u64(n+1))) {
20229 FatalErrorExit("command.bad_alloc_at field:command.gcli.fields comment:'index out of range'");
20230 }
20231 algo::cstring *elems = parent.fields_elems;
20232 memmove(elems + at + 1, elems + at, (n - at) * sizeof(algo::cstring));
20233 new (elems + at) algo::cstring(""); // construct element, default initializer
20234 parent.fields_n = n+1;
20235 return elems[at];
20236}
20237
20238// --- command.gcli.fields.AllocN
20239// Reserve space. Insert N elements at the end of the array, return pointer to array
20240algo::aryptr<algo::cstring> command::fields_AllocN(command::gcli& parent, int n_elems) {
20241 fields_Reserve(parent, n_elems);
20242 int old_n = parent.fields_n;
20243 int new_n = old_n + n_elems;
20244 algo::cstring *elems = parent.fields_elems;
20245 for (int i = old_n; i < new_n; i++) {
20246 new (elems + i) algo::cstring(""); // construct new element, default initialize
20247 }
20248 parent.fields_n = new_n;
20249 return algo::aryptr<algo::cstring>(elems + old_n, n_elems);
20250}
20251
20252// --- command.gcli.fields.Remove
20253// Remove item by index. If index outside of range, do nothing.
20254void command::fields_Remove(command::gcli& parent, u32 i) {
20255 u32 lim = parent.fields_n;
20256 algo::cstring *elems = parent.fields_elems;
20257 if (i < lim) {
20258 elems[i].~cstring(); // destroy element
20259 memmove(elems + i, elems + (i + 1), sizeof(algo::cstring) * (lim - (i + 1)));
20260 parent.fields_n = lim - 1;
20261 }
20262}
20263
20264// --- command.gcli.fields.RemoveAll
20265void command::fields_RemoveAll(command::gcli& parent) {
20266 u32 n = parent.fields_n;
20267 while (n > 0) {
20268 n -= 1;
20269 parent.fields_elems[n].~cstring();
20270 parent.fields_n = n;
20271 }
20272}
20273
20274// --- command.gcli.fields.RemoveLast
20275// Delete last element of array. Do nothing if array is empty.
20276void command::fields_RemoveLast(command::gcli& parent) {
20277 u64 n = parent.fields_n;
20278 if (n > 0) {
20279 n -= 1;
20280 fields_qFind(parent, u64(n)).~cstring();
20281 parent.fields_n = n;
20282 }
20283}
20284
20285// --- command.gcli.fields.AbsReserve
20286// Make sure N elements fit in array. Process dies if out of memory
20287void command::fields_AbsReserve(command::gcli& parent, int n) {
20288 u32 old_max = parent.fields_max;
20289 if (n > i32(old_max)) {
20290 u32 new_max = i32_Max(i32_Max(old_max * 2, n), 4);
20291 void *new_mem = algo_lib::malloc_ReallocMem(parent.fields_elems, old_max * sizeof(algo::cstring), new_max * sizeof(algo::cstring));
20292 if (UNLIKELY(!new_mem)) {
20293 FatalErrorExit("command.tary_nomem field:command.gcli.fields comment:'out of memory'");
20294 }
20295 parent.fields_elems = (algo::cstring*)new_mem;
20296 parent.fields_max = new_max;
20297 }
20298}
20299
20300// --- command.gcli.fields.Setary
20301// Copy contents of RHS to PARENT.
20302void command::fields_Setary(command::gcli& parent, command::gcli &rhs) {
20303 fields_RemoveAll(parent);
20304 int nnew = rhs.fields_n;
20305 fields_Reserve(parent, nnew); // reserve space
20306 for (int i = 0; i < nnew; i++) { // copy elements over
20307 new (parent.fields_elems + i) algo::cstring(fields_qFind(rhs, i));
20308 parent.fields_n = i + 1;
20309 }
20310}
20311
20312// --- command.gcli.fields.Setary2
20313// Copy specified array into fields, discarding previous contents.
20314// If the RHS argument aliases the array (refers to the same memory), throw exception.
20315void command::fields_Setary(command::gcli& parent, const algo::aryptr<algo::cstring> &rhs) {
20316 fields_RemoveAll(parent);
20317 fields_Addary(parent, rhs);
20318}
20319
20320// --- command.gcli.fields.AllocNVal
20321// Reserve space. Insert N elements at the end of the array, return pointer to array
20322algo::aryptr<algo::cstring> command::fields_AllocNVal(command::gcli& parent, int n_elems, const algo::cstring& val) {
20323 fields_Reserve(parent, n_elems);
20324 int old_n = parent.fields_n;
20325 int new_n = old_n + n_elems;
20326 algo::cstring *elems = parent.fields_elems;
20327 for (int i = old_n; i < new_n; i++) {
20328 new (elems + i) algo::cstring(val);
20329 }
20330 parent.fields_n = new_n;
20331 return algo::aryptr<algo::cstring>(elems + old_n, n_elems);
20332}
20333
20334// --- command.gcli.fields.ReadStrptrMaybe
20335// A single element is read from input string and appended to the array.
20336// If the string contains an error, the array is untouched.
20337// Function returns success value.
20338bool command::fields_ReadStrptrMaybe(command::gcli& parent, algo::strptr in_str) {
20339 bool retval = true;
20340 algo::cstring &elem = fields_Alloc(parent);
20341 retval = algo::cstring_ReadStrptrMaybe(elem, in_str);
20342 if (!retval) {
20343 fields_RemoveLast(parent);
20344 }
20345 return retval;
20346}
20347
20348// --- command.gcli..ReadFieldMaybe
20349bool command::gcli_ReadFieldMaybe(command::gcli& parent, algo::strptr field, algo::strptr strval) {
20350 bool retval = true;
20351 command::FieldId field_id;
20352 (void)value_SetStrptrMaybe(field_id,algo::Pathcomp(field, ".LL"));
20353 switch(field_id) {
20354 case command_FieldId_in: {
20355 retval = algo::cstring_ReadStrptrMaybe(parent.in, strval);
20356 break;
20357 }
20358 case command_FieldId_selector: {
20359 retval = algo::Smallstr250_ReadStrptrMaybe(parent.selector, strval);
20360 break;
20361 }
20362 case command_FieldId_fields: {
20363 retval = fields_ReadStrptrMaybe(parent, strval);
20364 break;
20365 }
20366 case command_FieldId_accept: {
20367 retval = bool_ReadStrptrMaybe(parent.accept, strval);
20368 break;
20369 }
20370 case command_FieldId_start: {
20371 retval = bool_ReadStrptrMaybe(parent.start, strval);
20372 break;
20373 }
20374 case command_FieldId_list: {
20375 retval = bool_ReadStrptrMaybe(parent.list, strval);
20376 break;
20377 }
20378 case command_FieldId_create: {
20379 retval = bool_ReadStrptrMaybe(parent.create, strval);
20380 break;
20381 }
20382 case command_FieldId_update: {
20383 retval = bool_ReadStrptrMaybe(parent.update, strval);
20384 break;
20385 }
20386 case command_FieldId_approve: {
20387 retval = bool_ReadStrptrMaybe(parent.approve, strval);
20388 break;
20389 }
20390 case command_FieldId_needs_work: {
20391 retval = bool_ReadStrptrMaybe(parent.needs_work, strval);
20392 break;
20393 }
20394 case command_FieldId_stop: {
20395 retval = bool_ReadStrptrMaybe(parent.stop, strval);
20396 break;
20397 }
20398 case command_FieldId_t: {
20399 retval = bool_ReadStrptrMaybe(parent.t, strval);
20400 break;
20401 }
20402 case command_FieldId_e: {
20403 retval = bool_ReadStrptrMaybe(parent.e, strval);
20404 break;
20405 }
20406 case command_FieldId_authdir: {
20407 retval = algo::cstring_ReadStrptrMaybe(parent.authdir, strval);
20408 break;
20409 }
20410 case command_FieldId_dry_run: {
20411 retval = bool_ReadStrptrMaybe(parent.dry_run, strval);
20412 break;
20413 }
20414 case command_FieldId_gitdir: {
20415 retval = algo::cstring_ReadStrptrMaybe(parent.gitdir, strval);
20416 break;
20417 }
20418 case command_FieldId_show_gitlab_system_notes: {
20419 retval = bool_ReadStrptrMaybe(parent.show_gitlab_system_notes, strval);
20420 break;
20421 }
20422 default: break;
20423 }
20424 if (!retval) {
20425 algo_lib::AppendErrtext("attr",field);
20426 }
20427 return retval;
20428}
20429
20430// --- command.gcli..ReadTupleMaybe
20431// Read fields of command::gcli from attributes of ascii tuple TUPLE
20432bool command::gcli_ReadTupleMaybe(command::gcli &parent, algo::Tuple &tuple) {
20433 bool retval = true;
20434 int anon_idx = 0;
20435 ind_beg(algo::Tuple_attrs_curs,attr,tuple) {
20436 if (ch_N(attr.name) == 0) {
20437 attr.name = gcli_GetAnon(parent, anon_idx++);
20438 }
20439 retval = gcli_ReadFieldMaybe(parent, attr.name, attr.value);
20440 if (!retval) {
20441 break;
20442 }
20443 }ind_end;
20444 return retval;
20445}
20446
20447// --- command.gcli..Init
20448// Set all fields to initial values.
20449void command::gcli_Init(command::gcli& parent) {
20450 parent.in = algo::strptr("data");
20451 parent.selector = algo::strptr("issue:%");
20452 parent.fields_elems = 0; // (command.gcli.fields)
20453 parent.fields_n = 0; // (command.gcli.fields)
20454 parent.fields_max = 0; // (command.gcli.fields)
20455 parent.accept = bool(false);
20456 parent.start = bool(false);
20457 parent.list = bool(false);
20458 parent.create = bool(false);
20459 parent.update = bool(false);
20460 parent.approve = bool(false);
20461 parent.needs_work = bool(false);
20462 parent.stop = bool(false);
20463 parent.t = bool(false);
20464 parent.e = bool(false);
20465 parent.authdir = algo::strptr(".ssim");
20466 parent.dry_run = bool(false);
20467 parent.gitdir = algo::strptr("");
20468 parent.show_gitlab_system_notes = bool(false);
20469}
20470
20471// --- command.gcli..Uninit
20472void command::gcli_Uninit(command::gcli& parent) {
20473 command::gcli &row = parent; (void)row;
20474
20475 // command.gcli.fields.Uninit (Tary) //additional key:value pairs for use with -create, -list, -update
20476 // remove all elements from command.gcli.fields
20477 fields_RemoveAll(parent);
20478 // free memory for Tary command.gcli.fields
20479 algo_lib::malloc_FreeMem(parent.fields_elems, sizeof(algo::cstring)*parent.fields_max); // (command.gcli.fields)
20480}
20481
20482// --- command.gcli..ToCmdline
20483// Convenience function that returns a full command line
20484// Assume command is in a directory called bin
20485tempstr command::gcli_ToCmdline(command::gcli& row) {
20486 tempstr ret;
20487 ret << "bin/gcli ";
20488 gcli_PrintArgv(row, ret);
20489 // inherit less intense verbose, debug options
20490 for (int i = 1; i < algo_lib::_db.cmdline.verbose; i++) {
20491 ret << " -verbose";
20492 }
20493 for (int i = 1; i < algo_lib::_db.cmdline.debug; i++) {
20494 ret << " -debug";
20495 }
20496 return ret;
20497}
20498
20499// --- command.gcli..PrintArgv
20500// print string representation of ROW to string STR
20501// cfmt:command.gcli.Argv printfmt:Tuple
20502void command::gcli_PrintArgv(command::gcli& row, algo::cstring& str) {
20503 algo::tempstr temp;
20504 (void)temp;
20505 (void)str;
20506 if (!(row.in == "data")) {
20507 ch_RemoveAll(temp);
20508 cstring_Print(row.in, temp);
20509 str << " -in:";
20510 strptr_PrintBash(temp,str);
20511 }
20512 ch_RemoveAll(temp);
20513 Smallstr250_Print(row.selector, temp);
20514 str << " -selector:";
20515 strptr_PrintBash(temp,str);
20516 ind_beg(gcli_fields_curs,value,row) {
20517 ch_RemoveAll(temp);
20518 cstring_Print(value, temp);
20519 str << " -fields:";
20520 strptr_PrintBash(temp,str);
20521 }ind_end;
20522 if (!(row.accept == false)) {
20523 ch_RemoveAll(temp);
20524 bool_Print(row.accept, temp);
20525 str << " -accept:";
20526 strptr_PrintBash(temp,str);
20527 }
20528 if (!(row.start == false)) {
20529 ch_RemoveAll(temp);
20530 bool_Print(row.start, temp);
20531 str << " -start:";
20532 strptr_PrintBash(temp,str);
20533 }
20534 if (!(row.list == false)) {
20535 ch_RemoveAll(temp);
20536 bool_Print(row.list, temp);
20537 str << " -list:";
20538 strptr_PrintBash(temp,str);
20539 }
20540 if (!(row.create == false)) {
20541 ch_RemoveAll(temp);
20542 bool_Print(row.create, temp);
20543 str << " -create:";
20544 strptr_PrintBash(temp,str);
20545 }
20546 if (!(row.update == false)) {
20547 ch_RemoveAll(temp);
20548 bool_Print(row.update, temp);
20549 str << " -update:";
20550 strptr_PrintBash(temp,str);
20551 }
20552 if (!(row.approve == false)) {
20553 ch_RemoveAll(temp);
20554 bool_Print(row.approve, temp);
20555 str << " -approve:";
20556 strptr_PrintBash(temp,str);
20557 }
20558 if (!(row.needs_work == false)) {
20559 ch_RemoveAll(temp);
20560 bool_Print(row.needs_work, temp);
20561 str << " -needs_work:";
20562 strptr_PrintBash(temp,str);
20563 }
20564 if (!(row.stop == false)) {
20565 ch_RemoveAll(temp);
20566 bool_Print(row.stop, temp);
20567 str << " -stop:";
20568 strptr_PrintBash(temp,str);
20569 }
20570 if (!(row.t == false)) {
20571 ch_RemoveAll(temp);
20572 bool_Print(row.t, temp);
20573 str << " -t:";
20574 strptr_PrintBash(temp,str);
20575 }
20576 if (!(row.e == false)) {
20577 ch_RemoveAll(temp);
20578 bool_Print(row.e, temp);
20579 str << " -e:";
20580 strptr_PrintBash(temp,str);
20581 }
20582 if (!(row.authdir == ".ssim")) {
20583 ch_RemoveAll(temp);
20584 cstring_Print(row.authdir, temp);
20585 str << " -authdir:";
20586 strptr_PrintBash(temp,str);
20587 }
20588 if (!(row.dry_run == false)) {
20589 ch_RemoveAll(temp);
20590 bool_Print(row.dry_run, temp);
20591 str << " -dry_run:";
20592 strptr_PrintBash(temp,str);
20593 }
20594 if (!(row.gitdir == "")) {
20595 ch_RemoveAll(temp);
20596 cstring_Print(row.gitdir, temp);
20597 str << " -gitdir:";
20598 strptr_PrintBash(temp,str);
20599 }
20600 if (!(row.show_gitlab_system_notes == false)) {
20601 ch_RemoveAll(temp);
20602 bool_Print(row.show_gitlab_system_notes, temp);
20603 str << " -show_gitlab_system_notes:";
20604 strptr_PrintBash(temp,str);
20605 }
20606}
20607
20608// --- command.gcli..GetAnon
20609algo::strptr command::gcli_GetAnon(command::gcli &parent, i32 idx) {
20610 (void)parent;//only to avoid -Wunused-parameter
20611 switch(idx) {
20612 case(0): return strptr("selector", 8);
20613 default: return strptr("fields", 6);
20614 }
20615}
20616
20617// --- command.gcli..NArgs
20618// Used with command lines
20619// Return # of command-line arguments that must follow this argument
20620// If FIELD is invalid, return -1
20621i32 command::gcli_NArgs(command::FieldId field, algo::strptr& out_dflt, bool* out_anon) {
20622 i32 retval = 1;
20623 switch (field) {
20624 case command_FieldId_in: { // $comment
20625 *out_anon = false;
20626 } break;
20627 case command_FieldId_selector: { // $comment
20628 *out_anon = true;
20629 } break;
20630 case command_FieldId_fields: { // $comment
20631 *out_anon = true;
20632 } break;
20633 case command_FieldId_accept: { // $comment
20634 *out_anon = false;
20635 retval=0;
20636 out_dflt="Y";
20637 } break;
20638 case command_FieldId_start: { // bool: no argument required but value may be specified as accept:Y
20639 *out_anon = false;
20640 retval=0;
20641 out_dflt="Y";
20642 } break;
20643 case command_FieldId_list: { // bool: no argument required but value may be specified as start:Y
20644 *out_anon = false;
20645 retval=0;
20646 out_dflt="Y";
20647 } break;
20648 case command_FieldId_create: { // bool: no argument required but value may be specified as list:Y
20649 *out_anon = false;
20650 retval=0;
20651 out_dflt="Y";
20652 } break;
20653 case command_FieldId_update: { // bool: no argument required but value may be specified as create:Y
20654 *out_anon = false;
20655 retval=0;
20656 out_dflt="Y";
20657 } break;
20658 case command_FieldId_approve: { // bool: no argument required but value may be specified as update:Y
20659 *out_anon = false;
20660 retval=0;
20661 out_dflt="Y";
20662 } break;
20663 case command_FieldId_needs_work: { // bool: no argument required but value may be specified as approve:Y
20664 *out_anon = false;
20665 retval=0;
20666 out_dflt="Y";
20667 } break;
20668 case command_FieldId_stop: { // bool: no argument required but value may be specified as needs_work:Y
20669 *out_anon = false;
20670 retval=0;
20671 out_dflt="Y";
20672 } break;
20673 case command_FieldId_t: { // bool: no argument required but value may be specified as stop:Y
20674 *out_anon = false;
20675 retval=0;
20676 out_dflt="Y";
20677 } break;
20678 case command_FieldId_e: { // bool: no argument required but value may be specified as t:Y
20679 *out_anon = false;
20680 retval=0;
20681 out_dflt="Y";
20682 } break;
20683 case command_FieldId_authdir: { // bool: no argument required but value may be specified as e:Y
20684 *out_anon = false;
20685 } break;
20686 case command_FieldId_dry_run: { // bool: no argument required but value may be specified as e:Y
20687 *out_anon = false;
20688 retval=0;
20689 out_dflt="Y";
20690 } break;
20691 case command_FieldId_gitdir: { // bool: no argument required but value may be specified as dry_run:Y
20692 *out_anon = false;
20693 } break;
20694 case command_FieldId_show_gitlab_system_notes: { // bool: no argument required but value may be specified as dry_run:Y
20695 *out_anon = false;
20696 retval=0;
20697 out_dflt="Y";
20698 } break;
20699 default:
20700 retval=-1; // unrecognized
20701 }
20702 return retval;
20703}
20704
20705// --- command.gcli_proc.gcli.Start
20706// Start subprocess
20707// If subprocess already running, do nothing. Otherwise, start it
20708int command::gcli_Start(command::gcli_proc& parent) {
20709 int retval = 0;
20710 if (parent.pid == 0) {
20711 verblog(gcli_ToCmdline(parent)); // maybe print command
20712#ifdef WIN32
20713 algo_lib::ResolveExecFname(parent.path);
20714 tempstr cmdline(gcli_ToCmdline(parent));
20715 parent.pid = dospawn(Zeroterm(parent.path),Zeroterm(cmdline),parent.timeout,parent.fstdin,parent.fstdout,parent.fstderr);
20716#else
20717 parent.pid = fork();
20718 if (parent.pid == 0) { // child
20719 algo_lib::DieWithParent();
20720 if (parent.timeout > 0) {
20721 alarm(parent.timeout);
20722 }
20723 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstdin , 0);
20724 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstdout, 1);
20725 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstderr, 2);
20726 if (retval==0) retval= gcli_Execv(parent);
20727 if (retval != 0) { // if start fails, print error
20728 int err=errno;
20729 prerr("command.gcli_execv"
20730 <<Keyval("errno",err)
20731 <<Keyval("errstr",strerror(err))
20732 <<Keyval("comment","Execv failed"));
20733 }
20734 _exit(127); // if failed to start, exit anyway
20735 } else if (parent.pid == -1) {
20736 retval = errno; // failed to fork
20737 }
20738#endif
20739 }
20740 parent.status = parent.pid > 0 ? 0 : -1; // if didn't start, set error status
20741 return retval;
20742}
20743
20744// --- command.gcli_proc.gcli.StartRead
20745// Start subprocess & Read output
20746algo::Fildes command::gcli_StartRead(command::gcli_proc& parent, algo_lib::FFildes &read) {
20747 int pipefd[2];
20748 int rc=pipe(pipefd);
20749 (void)rc;
20750 read.fd.value = pipefd[0];
20751 parent.fstdout << ">&" << pipefd[1];
20752 gcli_Start(parent);
20753 (void)close(pipefd[1]);
20754 return read.fd;
20755}
20756
20757// --- command.gcli_proc.gcli.Kill
20758// Kill subprocess and wait
20759void command::gcli_Kill(command::gcli_proc& parent) {
20760 if (parent.pid != 0) {
20761 kill(parent.pid,9);
20762 gcli_Wait(parent);
20763 }
20764}
20765
20766// --- command.gcli_proc.gcli.Wait
20767// Wait for subprocess to return
20768void command::gcli_Wait(command::gcli_proc& parent) {
20769 if (parent.pid > 0) {
20770 int wait_flags = 0;
20771 int wait_status = 0;
20772 int rc = -1;
20773 do {
20774 // really wait for subprocess to exit
20775 rc = waitpid(parent.pid,&wait_status,wait_flags);
20776 } while (rc==-1 && errno==EINTR);
20777 if (rc == parent.pid) {
20778 parent.status = wait_status;
20779 parent.pid = 0;
20780 }
20781 }
20782}
20783
20784// --- command.gcli_proc.gcli.Exec
20785// Start + Wait
20786// Execute subprocess and return exit code
20787int command::gcli_Exec(command::gcli_proc& parent) {
20788 gcli_Start(parent);
20789 gcli_Wait(parent);
20790 return parent.status;
20791}
20792
20793// --- command.gcli_proc.gcli.ExecX
20794// Start + Wait, throw exception on error
20795// Execute subprocess; throw human-readable exception on error
20796void command::gcli_ExecX(command::gcli_proc& parent) {
20797 int rc = gcli_Exec(parent);
20798 vrfy(rc==0, tempstr() << "algo_lib.exec" << Keyval("cmd",gcli_ToCmdline(parent))
20799 << Keyval("comment",algo::DescribeWaitStatus(parent.status)));
20800}
20801
20802// --- command.gcli_proc.gcli.Execv
20803// Call execv()
20804// Call execv with specified parameters
20805int command::gcli_Execv(command::gcli_proc& parent) {
20806 int ret = 0;
20807 algo::StringAry args;
20808 gcli_ToArgv(parent, args);
20809 char **argv = (char**)alloca((ary_N(args)+1)*sizeof(*argv));
20810 ind_beg(algo::StringAry_ary_curs,arg,args) {
20811 argv[ind_curs(arg).index] = Zeroterm(arg);
20812 }ind_end;
20813 argv[ary_N(args)] = NULL;
20814 // if parent.path is relative, search for it in PATH
20815 algo_lib::ResolveExecFname(parent.path);
20816 ret = execv(Zeroterm(parent.path),argv);
20817 return ret;
20818}
20819
20820// --- command.gcli_proc.gcli.ToCmdline
20821algo::tempstr command::gcli_ToCmdline(command::gcli_proc& parent) {
20822 algo::tempstr retval;
20823 retval << parent.path << " ";
20824 command::gcli_PrintArgv(parent.cmd,retval);
20825 if (ch_N(parent.fstdin)) {
20826 retval << " " << parent.fstdin;
20827 }
20828 if (ch_N(parent.fstdout)) {
20829 retval << " " << parent.fstdout;
20830 }
20831 if (ch_N(parent.fstderr)) {
20832 retval << " 2" << parent.fstderr;
20833 }
20834 return retval;
20835}
20836
20837// --- command.gcli_proc.gcli.ToArgv
20838// Form array from the command line
20839void command::gcli_ToArgv(command::gcli_proc& parent, algo::StringAry& args) {
20840 ary_RemoveAll(args);
20841 ary_Alloc(args) << parent.path;
20842
20843 if (parent.cmd.in != "data") {
20844 cstring *arg = &ary_Alloc(args);
20845 *arg << "-in:";
20846 cstring_Print(parent.cmd.in, *arg);
20847 }
20848
20849 if (parent.cmd.selector != "issue:%") {
20850 cstring *arg = &ary_Alloc(args);
20851 *arg << "-selector:";
20852 Smallstr250_Print(parent.cmd.selector, *arg);
20853 }
20854 ind_beg(command::gcli_fields_curs,value,parent.cmd) {
20855 cstring *arg = &ary_Alloc(args);
20856 *arg << "-fields:";
20857 cstring_Print(value, *arg);
20858 }ind_end;
20859
20860 if (parent.cmd.accept != false) {
20861 cstring *arg = &ary_Alloc(args);
20862 *arg << "-accept:";
20863 bool_Print(parent.cmd.accept, *arg);
20864 }
20865
20866 if (parent.cmd.start != false) {
20867 cstring *arg = &ary_Alloc(args);
20868 *arg << "-start:";
20869 bool_Print(parent.cmd.start, *arg);
20870 }
20871
20872 if (parent.cmd.list != false) {
20873 cstring *arg = &ary_Alloc(args);
20874 *arg << "-list:";
20875 bool_Print(parent.cmd.list, *arg);
20876 }
20877
20878 if (parent.cmd.create != false) {
20879 cstring *arg = &ary_Alloc(args);
20880 *arg << "-create:";
20881 bool_Print(parent.cmd.create, *arg);
20882 }
20883
20884 if (parent.cmd.update != false) {
20885 cstring *arg = &ary_Alloc(args);
20886 *arg << "-update:";
20887 bool_Print(parent.cmd.update, *arg);
20888 }
20889
20890 if (parent.cmd.approve != false) {
20891 cstring *arg = &ary_Alloc(args);
20892 *arg << "-approve:";
20893 bool_Print(parent.cmd.approve, *arg);
20894 }
20895
20896 if (parent.cmd.needs_work != false) {
20897 cstring *arg = &ary_Alloc(args);
20898 *arg << "-needs_work:";
20899 bool_Print(parent.cmd.needs_work, *arg);
20900 }
20901
20902 if (parent.cmd.stop != false) {
20903 cstring *arg = &ary_Alloc(args);
20904 *arg << "-stop:";
20905 bool_Print(parent.cmd.stop, *arg);
20906 }
20907
20908 if (parent.cmd.t != false) {
20909 cstring *arg = &ary_Alloc(args);
20910 *arg << "-t:";
20911 bool_Print(parent.cmd.t, *arg);
20912 }
20913
20914 if (parent.cmd.e != false) {
20915 cstring *arg = &ary_Alloc(args);
20916 *arg << "-e:";
20917 bool_Print(parent.cmd.e, *arg);
20918 }
20919
20920 if (parent.cmd.authdir != ".ssim") {
20921 cstring *arg = &ary_Alloc(args);
20922 *arg << "-authdir:";
20923 cstring_Print(parent.cmd.authdir, *arg);
20924 }
20925
20926 if (parent.cmd.dry_run != false) {
20927 cstring *arg = &ary_Alloc(args);
20928 *arg << "-dry_run:";
20929 bool_Print(parent.cmd.dry_run, *arg);
20930 }
20931
20932 if (parent.cmd.gitdir != "") {
20933 cstring *arg = &ary_Alloc(args);
20934 *arg << "-gitdir:";
20935 cstring_Print(parent.cmd.gitdir, *arg);
20936 }
20937
20938 if (parent.cmd.show_gitlab_system_notes != false) {
20939 cstring *arg = &ary_Alloc(args);
20940 *arg << "-show_gitlab_system_notes:";
20941 bool_Print(parent.cmd.show_gitlab_system_notes, *arg);
20942 }
20943 for (int i=1; i < algo_lib::_db.cmdline.verbose; ++i) {
20944 ary_Alloc(args) << "-verbose";
20945 }
20946}
20947
20948// --- command.gcli_proc..Uninit
20949void command::gcli_proc_Uninit(command::gcli_proc& parent) {
20950 command::gcli_proc &row = parent; (void)row;
20951
20952 // command.gcli_proc.gcli.Uninit (Exec) //
20953 gcli_Kill(parent); // kill child, ensure forward progress
20954}
20955
20956// --- command.gmv.gmvproj.Print
20957// Print back to string
20958void command::gmvproj_Print(command::gmv& parent, algo::cstring &out) {
20959 Regx_Print(parent.gmvproj, out);
20960}
20961
20962// --- command.gmv.gmvproj.ReadStrptrMaybe
20963// Read Regx from string
20964// Convert string to field. Return success value
20965bool command::gmvproj_ReadStrptrMaybe(command::gmv& parent, algo::strptr in) {
20966 bool retval = true;
20967 Regx_ReadSql(parent.gmvproj, in, true);
20968 return retval;
20969}
20970
20971// --- command.gmv..ReadFieldMaybe
20972bool command::gmv_ReadFieldMaybe(command::gmv& parent, algo::strptr field, algo::strptr strval) {
20973 bool retval = true;
20974 command::FieldId field_id;
20975 (void)value_SetStrptrMaybe(field_id,field);
20976 switch(field_id) {
20977 case command_FieldId_in: {
20978 retval = algo::cstring_ReadStrptrMaybe(parent.in, strval);
20979 break;
20980 }
20981 case command_FieldId_gmvproj: {
20982 retval = gmvproj_ReadStrptrMaybe(parent, strval);
20983 break;
20984 }
20985 case command_FieldId_move_out: {
20986 retval = bool_ReadStrptrMaybe(parent.move_out, strval);
20987 break;
20988 }
20989 case command_FieldId_move_in: {
20990 retval = bool_ReadStrptrMaybe(parent.move_in, strval);
20991 break;
20992 }
20993 case command_FieldId_commit: {
20994 retval = bool_ReadStrptrMaybe(parent.commit, strval);
20995 break;
20996 }
20997 case command_FieldId_no_rebase: {
20998 retval = bool_ReadStrptrMaybe(parent.no_rebase, strval);
20999 break;
21000 }
21001 case command_FieldId_dry_run: {
21002 retval = bool_ReadStrptrMaybe(parent.dry_run, strval);
21003 break;
21004 }
21005 default: break;
21006 }
21007 if (!retval) {
21008 algo_lib::AppendErrtext("attr",field);
21009 }
21010 return retval;
21011}
21012
21013// --- command.gmv..ReadTupleMaybe
21014// Read fields of command::gmv from attributes of ascii tuple TUPLE
21015bool command::gmv_ReadTupleMaybe(command::gmv &parent, algo::Tuple &tuple) {
21016 bool retval = true;
21017 ind_beg(algo::Tuple_attrs_curs,attr,tuple) {
21018 retval = gmv_ReadFieldMaybe(parent, attr.name, attr.value);
21019 if (!retval) {
21020 break;
21021 }
21022 }ind_end;
21023 return retval;
21024}
21025
21026// --- command.gmv..Init
21027// Set all fields to initial values.
21028void command::gmv_Init(command::gmv& parent) {
21029 parent.in = algo::strptr("data");
21030 Regx_ReadSql(parent.gmvproj, "wiki-algornd", true);
21031 parent.move_out = bool(false);
21032 parent.move_in = bool(false);
21033 parent.commit = bool(false);
21034 parent.no_rebase = bool(false);
21035 parent.dry_run = bool(false);
21036}
21037
21038// --- command.gmv..ToCmdline
21039// Convenience function that returns a full command line
21040// Assume command is in a directory called bin
21041tempstr command::gmv_ToCmdline(command::gmv& row) {
21042 tempstr ret;
21043 ret << "bin/gmv ";
21044 gmv_PrintArgv(row, ret);
21045 // inherit less intense verbose, debug options
21046 for (int i = 1; i < algo_lib::_db.cmdline.verbose; i++) {
21047 ret << " -verbose";
21048 }
21049 for (int i = 1; i < algo_lib::_db.cmdline.debug; i++) {
21050 ret << " -debug";
21051 }
21052 return ret;
21053}
21054
21055// --- command.gmv..PrintArgv
21056// print string representation of ROW to string STR
21057// cfmt:command.gmv.Argv printfmt:Tuple
21058void command::gmv_PrintArgv(command::gmv& row, algo::cstring& str) {
21059 algo::tempstr temp;
21060 (void)temp;
21061 (void)str;
21062 if (!(row.in == "data")) {
21063 ch_RemoveAll(temp);
21064 cstring_Print(row.in, temp);
21065 str << " -in:";
21066 strptr_PrintBash(temp,str);
21067 }
21068 if (!(row.gmvproj.expr == "wiki-algornd")) {
21069 ch_RemoveAll(temp);
21070 command::gmvproj_Print(const_cast<command::gmv&>(row), temp);
21071 str << " -gmvproj:";
21072 strptr_PrintBash(temp,str);
21073 }
21074 if (!(row.move_out == false)) {
21075 ch_RemoveAll(temp);
21076 bool_Print(row.move_out, temp);
21077 str << " -move_out:";
21078 strptr_PrintBash(temp,str);
21079 }
21080 if (!(row.move_in == false)) {
21081 ch_RemoveAll(temp);
21082 bool_Print(row.move_in, temp);
21083 str << " -move_in:";
21084 strptr_PrintBash(temp,str);
21085 }
21086 if (!(row.commit == false)) {
21087 ch_RemoveAll(temp);
21088 bool_Print(row.commit, temp);
21089 str << " -commit:";
21090 strptr_PrintBash(temp,str);
21091 }
21092 if (!(row.no_rebase == false)) {
21093 ch_RemoveAll(temp);
21094 bool_Print(row.no_rebase, temp);
21095 str << " -no_rebase:";
21096 strptr_PrintBash(temp,str);
21097 }
21098 if (!(row.dry_run == false)) {
21099 ch_RemoveAll(temp);
21100 bool_Print(row.dry_run, temp);
21101 str << " -dry_run:";
21102 strptr_PrintBash(temp,str);
21103 }
21104}
21105
21106// --- command.gmv..NArgs
21107// Used with command lines
21108// Return # of command-line arguments that must follow this argument
21109// If FIELD is invalid, return -1
21110i32 command::gmv_NArgs(command::FieldId field, algo::strptr& out_dflt, bool* out_anon) {
21111 i32 retval = 1;
21112 switch (field) {
21113 case command_FieldId_in: { // $comment
21114 *out_anon = false;
21115 } break;
21116 case command_FieldId_gmvproj: { // $comment
21117 *out_anon = false;
21118 } break;
21119 case command_FieldId_move_out: { // $comment
21120 *out_anon = false;
21121 retval=0;
21122 out_dflt="Y";
21123 } break;
21124 case command_FieldId_move_in: { // bool: no argument required but value may be specified as move_out:Y
21125 *out_anon = false;
21126 retval=0;
21127 out_dflt="Y";
21128 } break;
21129 case command_FieldId_commit: { // bool: no argument required but value may be specified as move_in:Y
21130 *out_anon = false;
21131 retval=0;
21132 out_dflt="Y";
21133 } break;
21134 case command_FieldId_no_rebase: { // bool: no argument required but value may be specified as commit:Y
21135 *out_anon = false;
21136 retval=0;
21137 out_dflt="Y";
21138 } break;
21139 case command_FieldId_dry_run: { // bool: no argument required but value may be specified as no_rebase:Y
21140 *out_anon = false;
21141 retval=0;
21142 out_dflt="Y";
21143 } break;
21144 default:
21145 retval=-1; // unrecognized
21146 }
21147 return retval;
21148}
21149
21150// --- command.gmv_proc.gmv.Start
21151// Start subprocess
21152// If subprocess already running, do nothing. Otherwise, start it
21153int command::gmv_Start(command::gmv_proc& parent) {
21154 int retval = 0;
21155 if (parent.pid == 0) {
21156 verblog(gmv_ToCmdline(parent)); // maybe print command
21157#ifdef WIN32
21158 algo_lib::ResolveExecFname(parent.path);
21159 tempstr cmdline(gmv_ToCmdline(parent));
21160 parent.pid = dospawn(Zeroterm(parent.path),Zeroterm(cmdline),parent.timeout,parent.fstdin,parent.fstdout,parent.fstderr);
21161#else
21162 parent.pid = fork();
21163 if (parent.pid == 0) { // child
21164 algo_lib::DieWithParent();
21165 if (parent.timeout > 0) {
21166 alarm(parent.timeout);
21167 }
21168 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstdin , 0);
21169 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstdout, 1);
21170 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstderr, 2);
21171 if (retval==0) retval= gmv_Execv(parent);
21172 if (retval != 0) { // if start fails, print error
21173 int err=errno;
21174 prerr("command.gmv_execv"
21175 <<Keyval("errno",err)
21176 <<Keyval("errstr",strerror(err))
21177 <<Keyval("comment","Execv failed"));
21178 }
21179 _exit(127); // if failed to start, exit anyway
21180 } else if (parent.pid == -1) {
21181 retval = errno; // failed to fork
21182 }
21183#endif
21184 }
21185 parent.status = parent.pid > 0 ? 0 : -1; // if didn't start, set error status
21186 return retval;
21187}
21188
21189// --- command.gmv_proc.gmv.StartRead
21190// Start subprocess & Read output
21191algo::Fildes command::gmv_StartRead(command::gmv_proc& parent, algo_lib::FFildes &read) {
21192 int pipefd[2];
21193 int rc=pipe(pipefd);
21194 (void)rc;
21195 read.fd.value = pipefd[0];
21196 parent.fstdout << ">&" << pipefd[1];
21197 gmv_Start(parent);
21198 (void)close(pipefd[1]);
21199 return read.fd;
21200}
21201
21202// --- command.gmv_proc.gmv.Kill
21203// Kill subprocess and wait
21204void command::gmv_Kill(command::gmv_proc& parent) {
21205 if (parent.pid != 0) {
21206 kill(parent.pid,9);
21207 gmv_Wait(parent);
21208 }
21209}
21210
21211// --- command.gmv_proc.gmv.Wait
21212// Wait for subprocess to return
21213void command::gmv_Wait(command::gmv_proc& parent) {
21214 if (parent.pid > 0) {
21215 int wait_flags = 0;
21216 int wait_status = 0;
21217 int rc = -1;
21218 do {
21219 // really wait for subprocess to exit
21220 rc = waitpid(parent.pid,&wait_status,wait_flags);
21221 } while (rc==-1 && errno==EINTR);
21222 if (rc == parent.pid) {
21223 parent.status = wait_status;
21224 parent.pid = 0;
21225 }
21226 }
21227}
21228
21229// --- command.gmv_proc.gmv.Exec
21230// Start + Wait
21231// Execute subprocess and return exit code
21232int command::gmv_Exec(command::gmv_proc& parent) {
21233 gmv_Start(parent);
21234 gmv_Wait(parent);
21235 return parent.status;
21236}
21237
21238// --- command.gmv_proc.gmv.ExecX
21239// Start + Wait, throw exception on error
21240// Execute subprocess; throw human-readable exception on error
21241void command::gmv_ExecX(command::gmv_proc& parent) {
21242 int rc = gmv_Exec(parent);
21243 vrfy(rc==0, tempstr() << "algo_lib.exec" << Keyval("cmd",gmv_ToCmdline(parent))
21244 << Keyval("comment",algo::DescribeWaitStatus(parent.status)));
21245}
21246
21247// --- command.gmv_proc.gmv.Execv
21248// Call execv()
21249// Call execv with specified parameters
21250int command::gmv_Execv(command::gmv_proc& parent) {
21251 int ret = 0;
21252 algo::StringAry args;
21253 gmv_ToArgv(parent, args);
21254 char **argv = (char**)alloca((ary_N(args)+1)*sizeof(*argv));
21255 ind_beg(algo::StringAry_ary_curs,arg,args) {
21256 argv[ind_curs(arg).index] = Zeroterm(arg);
21257 }ind_end;
21258 argv[ary_N(args)] = NULL;
21259 // if parent.path is relative, search for it in PATH
21260 algo_lib::ResolveExecFname(parent.path);
21261 ret = execv(Zeroterm(parent.path),argv);
21262 return ret;
21263}
21264
21265// --- command.gmv_proc.gmv.ToCmdline
21266algo::tempstr command::gmv_ToCmdline(command::gmv_proc& parent) {
21267 algo::tempstr retval;
21268 retval << parent.path << " ";
21269 command::gmv_PrintArgv(parent.cmd,retval);
21270 if (ch_N(parent.fstdin)) {
21271 retval << " " << parent.fstdin;
21272 }
21273 if (ch_N(parent.fstdout)) {
21274 retval << " " << parent.fstdout;
21275 }
21276 if (ch_N(parent.fstderr)) {
21277 retval << " 2" << parent.fstderr;
21278 }
21279 return retval;
21280}
21281
21282// --- command.gmv_proc.gmv.ToArgv
21283// Form array from the command line
21284void command::gmv_ToArgv(command::gmv_proc& parent, algo::StringAry& args) {
21285 ary_RemoveAll(args);
21286 ary_Alloc(args) << parent.path;
21287
21288 if (parent.cmd.in != "data") {
21289 cstring *arg = &ary_Alloc(args);
21290 *arg << "-in:";
21291 cstring_Print(parent.cmd.in, *arg);
21292 }
21293
21294 if (parent.cmd.gmvproj.expr != "wiki-algornd") {
21295 cstring *arg = &ary_Alloc(args);
21296 *arg << "-gmvproj:";
21297 command::gmvproj_Print(parent.cmd, *arg);
21298 }
21299
21300 if (parent.cmd.move_out != false) {
21301 cstring *arg = &ary_Alloc(args);
21302 *arg << "-move_out:";
21303 bool_Print(parent.cmd.move_out, *arg);
21304 }
21305
21306 if (parent.cmd.move_in != false) {
21307 cstring *arg = &ary_Alloc(args);
21308 *arg << "-move_in:";
21309 bool_Print(parent.cmd.move_in, *arg);
21310 }
21311
21312 if (parent.cmd.commit != false) {
21313 cstring *arg = &ary_Alloc(args);
21314 *arg << "-commit:";
21315 bool_Print(parent.cmd.commit, *arg);
21316 }
21317
21318 if (parent.cmd.no_rebase != false) {
21319 cstring *arg = &ary_Alloc(args);
21320 *arg << "-no_rebase:";
21321 bool_Print(parent.cmd.no_rebase, *arg);
21322 }
21323
21324 if (parent.cmd.dry_run != false) {
21325 cstring *arg = &ary_Alloc(args);
21326 *arg << "-dry_run:";
21327 bool_Print(parent.cmd.dry_run, *arg);
21328 }
21329 for (int i=1; i < algo_lib::_db.cmdline.verbose; ++i) {
21330 ary_Alloc(args) << "-verbose";
21331 }
21332}
21333
21334// --- command.gmv_proc..Uninit
21335void command::gmv_proc_Uninit(command::gmv_proc& parent) {
21336 command::gmv_proc &row = parent; (void)row;
21337
21338 // command.gmv_proc.gmv.Uninit (Exec) //
21339 gmv_Kill(parent); // kill child, ensure forward progress
21340}
21341
21342// --- command.mdbg.args.Addary
21343// Reserve space (this may move memory). Insert N element at the end.
21344// Return aryptr to newly inserted block.
21345// If the RHS argument aliases the array (refers to the same memory), exit program with fatal error.
21346algo::aryptr<algo::cstring> command::args_Addary(command::mdbg& parent, algo::aryptr<algo::cstring> rhs) {
21347 bool overlaps = rhs.n_elems>0 && rhs.elems >= parent.args_elems && rhs.elems < parent.args_elems + parent.args_max;
21348 if (UNLIKELY(overlaps)) {
21349 FatalErrorExit("command.tary_alias field:command.mdbg.args comment:'alias error: sub-array is being appended to the whole'");
21350 }
21351 int nnew = rhs.n_elems;
21352 args_Reserve(parent, nnew); // reserve space
21353 int at = parent.args_n;
21354 for (int i = 0; i < nnew; i++) {
21355 new (parent.args_elems + at + i) algo::cstring(rhs[i]);
21356 parent.args_n++;
21357 }
21358 return algo::aryptr<algo::cstring>(parent.args_elems + at, nnew);
21359}
21360
21361// --- command.mdbg.args.Alloc
21362// Reserve space. Insert element at the end
21363// The new element is initialized to a default value
21364algo::cstring& command::args_Alloc(command::mdbg& parent) {
21365 args_Reserve(parent, 1);
21366 int n = parent.args_n;
21367 int at = n;
21368 algo::cstring *elems = parent.args_elems;
21369 new (elems + at) algo::cstring(""); // construct new element, default initializer
21370 parent.args_n = n+1;
21371 return elems[at];
21372}
21373
21374// --- command.mdbg.args.AllocAt
21375// Reserve space for new element, reallocating the array if necessary
21376// Insert new element at specified index. Index must be in range or a fatal error occurs.
21377algo::cstring& command::args_AllocAt(command::mdbg& parent, int at) {
21378 args_Reserve(parent, 1);
21379 int n = parent.args_n;
21380 if (UNLIKELY(u64(at) >= u64(n+1))) {
21381 FatalErrorExit("command.bad_alloc_at field:command.mdbg.args comment:'index out of range'");
21382 }
21383 algo::cstring *elems = parent.args_elems;
21384 memmove(elems + at + 1, elems + at, (n - at) * sizeof(algo::cstring));
21385 new (elems + at) algo::cstring(""); // construct element, default initializer
21386 parent.args_n = n+1;
21387 return elems[at];
21388}
21389
21390// --- command.mdbg.args.AllocN
21391// Reserve space. Insert N elements at the end of the array, return pointer to array
21392algo::aryptr<algo::cstring> command::args_AllocN(command::mdbg& parent, int n_elems) {
21393 args_Reserve(parent, n_elems);
21394 int old_n = parent.args_n;
21395 int new_n = old_n + n_elems;
21396 algo::cstring *elems = parent.args_elems;
21397 for (int i = old_n; i < new_n; i++) {
21398 new (elems + i) algo::cstring(""); // construct new element, default initialize
21399 }
21400 parent.args_n = new_n;
21401 return algo::aryptr<algo::cstring>(elems + old_n, n_elems);
21402}
21403
21404// --- command.mdbg.args.Remove
21405// Remove item by index. If index outside of range, do nothing.
21406void command::args_Remove(command::mdbg& parent, u32 i) {
21407 u32 lim = parent.args_n;
21408 algo::cstring *elems = parent.args_elems;
21409 if (i < lim) {
21410 elems[i].~cstring(); // destroy element
21411 memmove(elems + i, elems + (i + 1), sizeof(algo::cstring) * (lim - (i + 1)));
21412 parent.args_n = lim - 1;
21413 }
21414}
21415
21416// --- command.mdbg.args.RemoveAll
21417void command::args_RemoveAll(command::mdbg& parent) {
21418 u32 n = parent.args_n;
21419 while (n > 0) {
21420 n -= 1;
21421 parent.args_elems[n].~cstring();
21422 parent.args_n = n;
21423 }
21424}
21425
21426// --- command.mdbg.args.RemoveLast
21427// Delete last element of array. Do nothing if array is empty.
21428void command::args_RemoveLast(command::mdbg& parent) {
21429 u64 n = parent.args_n;
21430 if (n > 0) {
21431 n -= 1;
21432 args_qFind(parent, u64(n)).~cstring();
21433 parent.args_n = n;
21434 }
21435}
21436
21437// --- command.mdbg.args.AbsReserve
21438// Make sure N elements fit in array. Process dies if out of memory
21439void command::args_AbsReserve(command::mdbg& parent, int n) {
21440 u32 old_max = parent.args_max;
21441 if (n > i32(old_max)) {
21442 u32 new_max = i32_Max(i32_Max(old_max * 2, n), 4);
21443 void *new_mem = algo_lib::malloc_ReallocMem(parent.args_elems, old_max * sizeof(algo::cstring), new_max * sizeof(algo::cstring));
21444 if (UNLIKELY(!new_mem)) {
21445 FatalErrorExit("command.tary_nomem field:command.mdbg.args comment:'out of memory'");
21446 }
21447 parent.args_elems = (algo::cstring*)new_mem;
21448 parent.args_max = new_max;
21449 }
21450}
21451
21452// --- command.mdbg.args.Setary
21453// Copy contents of RHS to PARENT.
21454void command::args_Setary(command::mdbg& parent, command::mdbg &rhs) {
21455 args_RemoveAll(parent);
21456 int nnew = rhs.args_n;
21457 args_Reserve(parent, nnew); // reserve space
21458 for (int i = 0; i < nnew; i++) { // copy elements over
21459 new (parent.args_elems + i) algo::cstring(args_qFind(rhs, i));
21460 parent.args_n = i + 1;
21461 }
21462}
21463
21464// --- command.mdbg.args.Setary2
21465// Copy specified array into args, discarding previous contents.
21466// If the RHS argument aliases the array (refers to the same memory), throw exception.
21467void command::args_Setary(command::mdbg& parent, const algo::aryptr<algo::cstring> &rhs) {
21468 args_RemoveAll(parent);
21469 args_Addary(parent, rhs);
21470}
21471
21472// --- command.mdbg.args.AllocNVal
21473// Reserve space. Insert N elements at the end of the array, return pointer to array
21474algo::aryptr<algo::cstring> command::args_AllocNVal(command::mdbg& parent, int n_elems, const algo::cstring& val) {
21475 args_Reserve(parent, n_elems);
21476 int old_n = parent.args_n;
21477 int new_n = old_n + n_elems;
21478 algo::cstring *elems = parent.args_elems;
21479 for (int i = old_n; i < new_n; i++) {
21480 new (elems + i) algo::cstring(val);
21481 }
21482 parent.args_n = new_n;
21483 return algo::aryptr<algo::cstring>(elems + old_n, n_elems);
21484}
21485
21486// --- command.mdbg.args.ReadStrptrMaybe
21487// A single element is read from input string and appended to the array.
21488// If the string contains an error, the array is untouched.
21489// Function returns success value.
21490bool command::args_ReadStrptrMaybe(command::mdbg& parent, algo::strptr in_str) {
21491 bool retval = true;
21492 algo::cstring &elem = args_Alloc(parent);
21493 retval = algo::cstring_ReadStrptrMaybe(elem, in_str);
21494 if (!retval) {
21495 args_RemoveLast(parent);
21496 }
21497 return retval;
21498}
21499
21500// --- command.mdbg.b.Addary
21501// Reserve space (this may move memory). Insert N element at the end.
21502// Return aryptr to newly inserted block.
21503// If the RHS argument aliases the array (refers to the same memory), exit program with fatal error.
21504algo::aryptr<algo::cstring> command::b_Addary(command::mdbg& parent, algo::aryptr<algo::cstring> rhs) {
21505 bool overlaps = rhs.n_elems>0 && rhs.elems >= parent.b_elems && rhs.elems < parent.b_elems + parent.b_max;
21506 if (UNLIKELY(overlaps)) {
21507 FatalErrorExit("command.tary_alias field:command.mdbg.b comment:'alias error: sub-array is being appended to the whole'");
21508 }
21509 int nnew = rhs.n_elems;
21510 b_Reserve(parent, nnew); // reserve space
21511 int at = parent.b_n;
21512 for (int i = 0; i < nnew; i++) {
21513 new (parent.b_elems + at + i) algo::cstring(rhs[i]);
21514 parent.b_n++;
21515 }
21516 return algo::aryptr<algo::cstring>(parent.b_elems + at, nnew);
21517}
21518
21519// --- command.mdbg.b.Alloc
21520// Reserve space. Insert element at the end
21521// The new element is initialized to a default value
21522algo::cstring& command::b_Alloc(command::mdbg& parent) {
21523 b_Reserve(parent, 1);
21524 int n = parent.b_n;
21525 int at = n;
21526 algo::cstring *elems = parent.b_elems;
21527 new (elems + at) algo::cstring(""); // construct new element, default initializer
21528 parent.b_n = n+1;
21529 return elems[at];
21530}
21531
21532// --- command.mdbg.b.AllocAt
21533// Reserve space for new element, reallocating the array if necessary
21534// Insert new element at specified index. Index must be in range or a fatal error occurs.
21535algo::cstring& command::b_AllocAt(command::mdbg& parent, int at) {
21536 b_Reserve(parent, 1);
21537 int n = parent.b_n;
21538 if (UNLIKELY(u64(at) >= u64(n+1))) {
21539 FatalErrorExit("command.bad_alloc_at field:command.mdbg.b comment:'index out of range'");
21540 }
21541 algo::cstring *elems = parent.b_elems;
21542 memmove(elems + at + 1, elems + at, (n - at) * sizeof(algo::cstring));
21543 new (elems + at) algo::cstring(""); // construct element, default initializer
21544 parent.b_n = n+1;
21545 return elems[at];
21546}
21547
21548// --- command.mdbg.b.AllocN
21549// Reserve space. Insert N elements at the end of the array, return pointer to array
21550algo::aryptr<algo::cstring> command::b_AllocN(command::mdbg& parent, int n_elems) {
21551 b_Reserve(parent, n_elems);
21552 int old_n = parent.b_n;
21553 int new_n = old_n + n_elems;
21554 algo::cstring *elems = parent.b_elems;
21555 for (int i = old_n; i < new_n; i++) {
21556 new (elems + i) algo::cstring(""); // construct new element, default initialize
21557 }
21558 parent.b_n = new_n;
21559 return algo::aryptr<algo::cstring>(elems + old_n, n_elems);
21560}
21561
21562// --- command.mdbg.b.Remove
21563// Remove item by index. If index outside of range, do nothing.
21564void command::b_Remove(command::mdbg& parent, u32 i) {
21565 u32 lim = parent.b_n;
21566 algo::cstring *elems = parent.b_elems;
21567 if (i < lim) {
21568 elems[i].~cstring(); // destroy element
21569 memmove(elems + i, elems + (i + 1), sizeof(algo::cstring) * (lim - (i + 1)));
21570 parent.b_n = lim - 1;
21571 }
21572}
21573
21574// --- command.mdbg.b.RemoveAll
21575void command::b_RemoveAll(command::mdbg& parent) {
21576 u32 n = parent.b_n;
21577 while (n > 0) {
21578 n -= 1;
21579 parent.b_elems[n].~cstring();
21580 parent.b_n = n;
21581 }
21582}
21583
21584// --- command.mdbg.b.RemoveLast
21585// Delete last element of array. Do nothing if array is empty.
21586void command::b_RemoveLast(command::mdbg& parent) {
21587 u64 n = parent.b_n;
21588 if (n > 0) {
21589 n -= 1;
21590 b_qFind(parent, u64(n)).~cstring();
21591 parent.b_n = n;
21592 }
21593}
21594
21595// --- command.mdbg.b.AbsReserve
21596// Make sure N elements fit in array. Process dies if out of memory
21597void command::b_AbsReserve(command::mdbg& parent, int n) {
21598 u32 old_max = parent.b_max;
21599 if (n > i32(old_max)) {
21600 u32 new_max = i32_Max(i32_Max(old_max * 2, n), 4);
21601 void *new_mem = algo_lib::malloc_ReallocMem(parent.b_elems, old_max * sizeof(algo::cstring), new_max * sizeof(algo::cstring));
21602 if (UNLIKELY(!new_mem)) {
21603 FatalErrorExit("command.tary_nomem field:command.mdbg.b comment:'out of memory'");
21604 }
21605 parent.b_elems = (algo::cstring*)new_mem;
21606 parent.b_max = new_max;
21607 }
21608}
21609
21610// --- command.mdbg.b.Setary
21611// Copy contents of RHS to PARENT.
21612void command::b_Setary(command::mdbg& parent, command::mdbg &rhs) {
21613 b_RemoveAll(parent);
21614 int nnew = rhs.b_n;
21615 b_Reserve(parent, nnew); // reserve space
21616 for (int i = 0; i < nnew; i++) { // copy elements over
21617 new (parent.b_elems + i) algo::cstring(b_qFind(rhs, i));
21618 parent.b_n = i + 1;
21619 }
21620}
21621
21622// --- command.mdbg.b.Setary2
21623// Copy specified array into b, discarding previous contents.
21624// If the RHS argument aliases the array (refers to the same memory), throw exception.
21625void command::b_Setary(command::mdbg& parent, const algo::aryptr<algo::cstring> &rhs) {
21626 b_RemoveAll(parent);
21627 b_Addary(parent, rhs);
21628}
21629
21630// --- command.mdbg.b.AllocNVal
21631// Reserve space. Insert N elements at the end of the array, return pointer to array
21632algo::aryptr<algo::cstring> command::b_AllocNVal(command::mdbg& parent, int n_elems, const algo::cstring& val) {
21633 b_Reserve(parent, n_elems);
21634 int old_n = parent.b_n;
21635 int new_n = old_n + n_elems;
21636 algo::cstring *elems = parent.b_elems;
21637 for (int i = old_n; i < new_n; i++) {
21638 new (elems + i) algo::cstring(val);
21639 }
21640 parent.b_n = new_n;
21641 return algo::aryptr<algo::cstring>(elems + old_n, n_elems);
21642}
21643
21644// --- command.mdbg.b.ReadStrptrMaybe
21645// A single element is read from input string and appended to the array.
21646// If the string contains an error, the array is untouched.
21647// Function returns success value.
21648bool command::b_ReadStrptrMaybe(command::mdbg& parent, algo::strptr in_str) {
21649 bool retval = true;
21650 algo::cstring &elem = b_Alloc(parent);
21651 retval = algo::cstring_ReadStrptrMaybe(elem, in_str);
21652 if (!retval) {
21653 b_RemoveLast(parent);
21654 }
21655 return retval;
21656}
21657
21658// --- command.mdbg..ReadFieldMaybe
21659bool command::mdbg_ReadFieldMaybe(command::mdbg& parent, algo::strptr field, algo::strptr strval) {
21660 bool retval = true;
21661 command::FieldId field_id;
21662 (void)value_SetStrptrMaybe(field_id,algo::Pathcomp(field, ".LL"));
21663 switch(field_id) {
21664 case command_FieldId_target: {
21665 retval = algo::Smallstr16_ReadStrptrMaybe(parent.target, strval);
21666 break;
21667 }
21668 case command_FieldId_in: {
21669 retval = algo::cstring_ReadStrptrMaybe(parent.in, strval);
21670 break;
21671 }
21672 case command_FieldId_args: {
21673 retval = args_ReadStrptrMaybe(parent, strval);
21674 break;
21675 }
21676 case command_FieldId_cfg: {
21677 retval = algo::Smallstr50_ReadStrptrMaybe(parent.cfg, strval);
21678 break;
21679 }
21680 case command_FieldId_disas: {
21681 retval = bool_ReadStrptrMaybe(parent.disas, strval);
21682 break;
21683 }
21684 case command_FieldId_attach: {
21685 retval = bool_ReadStrptrMaybe(parent.attach, strval);
21686 break;
21687 }
21688 case command_FieldId_b: {
21689 retval = b_ReadStrptrMaybe(parent, strval);
21690 break;
21691 }
21692 case command_FieldId_catchthrow: {
21693 retval = bool_ReadStrptrMaybe(parent.catchthrow, strval);
21694 break;
21695 }
21696 case command_FieldId_tui: {
21697 retval = bool_ReadStrptrMaybe(parent.tui, strval);
21698 break;
21699 }
21700 case command_FieldId_bcmd: {
21701 retval = algo::cstring_ReadStrptrMaybe(parent.bcmd, strval);
21702 break;
21703 }
21704 case command_FieldId_emacs: {
21705 retval = bool_ReadStrptrMaybe(parent.emacs, strval);
21706 break;
21707 }
21708 case command_FieldId_manywin: {
21709 retval = bool_ReadStrptrMaybe(parent.manywin, strval);
21710 break;
21711 }
21712 case command_FieldId_follow_child: {
21713 retval = bool_ReadStrptrMaybe(parent.follow_child, strval);
21714 break;
21715 }
21716 case command_FieldId_py: {
21717 retval = bool_ReadStrptrMaybe(parent.py, strval);
21718 break;
21719 }
21720 case command_FieldId_dry_run: {
21721 retval = bool_ReadStrptrMaybe(parent.dry_run, strval);
21722 break;
21723 }
21724 default: break;
21725 }
21726 if (!retval) {
21727 algo_lib::AppendErrtext("attr",field);
21728 }
21729 return retval;
21730}
21731
21732// --- command.mdbg..ReadTupleMaybe
21733// Read fields of command::mdbg from attributes of ascii tuple TUPLE
21734bool command::mdbg_ReadTupleMaybe(command::mdbg &parent, algo::Tuple &tuple) {
21735 bool retval = true;
21736 int anon_idx = 0;
21737 ind_beg(algo::Tuple_attrs_curs,attr,tuple) {
21738 if (ch_N(attr.name) == 0) {
21739 attr.name = mdbg_GetAnon(parent, anon_idx++);
21740 }
21741 retval = mdbg_ReadFieldMaybe(parent, attr.name, attr.value);
21742 if (!retval) {
21743 break;
21744 }
21745 }ind_end;
21746 return retval;
21747}
21748
21749// --- command.mdbg..Init
21750// Set all fields to initial values.
21751void command::mdbg_Init(command::mdbg& parent) {
21752 parent.in = algo::strptr("data");
21753 parent.args_elems = 0; // (command.mdbg.args)
21754 parent.args_n = 0; // (command.mdbg.args)
21755 parent.args_max = 0; // (command.mdbg.args)
21756 parent.cfg = algo::strptr("debug");
21757 parent.disas = bool(false);
21758 parent.attach = bool(false);
21759 parent.b_elems = 0; // (command.mdbg.b)
21760 parent.b_n = 0; // (command.mdbg.b)
21761 parent.b_max = 0; // (command.mdbg.b)
21762 parent.catchthrow = bool(true);
21763 parent.tui = bool(false);
21764 parent.bcmd = algo::strptr("");
21765 parent.emacs = bool(true);
21766 parent.manywin = bool(false);
21767 parent.follow_child = bool(false);
21768 parent.py = bool(false);
21769 parent.dry_run = bool(false);
21770}
21771
21772// --- command.mdbg..Uninit
21773void command::mdbg_Uninit(command::mdbg& parent) {
21774 command::mdbg &row = parent; (void)row;
21775
21776 // command.mdbg.b.Uninit (Tary) //Set breakpoint, e.g. 'a.cpp:123 if cond1', 'func#3'
21777 // remove all elements from command.mdbg.b
21778 b_RemoveAll(parent);
21779 // free memory for Tary command.mdbg.b
21780 algo_lib::malloc_FreeMem(parent.b_elems, sizeof(algo::cstring)*parent.b_max); // (command.mdbg.b)
21781
21782 // command.mdbg.args.Uninit (Tary) //Additional module args
21783 // remove all elements from command.mdbg.args
21784 args_RemoveAll(parent);
21785 // free memory for Tary command.mdbg.args
21786 algo_lib::malloc_FreeMem(parent.args_elems, sizeof(algo::cstring)*parent.args_max); // (command.mdbg.args)
21787}
21788
21789// --- command.mdbg..ToCmdline
21790// Convenience function that returns a full command line
21791// Assume command is in a directory called bin
21792tempstr command::mdbg_ToCmdline(command::mdbg& row) {
21793 tempstr ret;
21794 ret << "bin/mdbg ";
21795 mdbg_PrintArgv(row, ret);
21796 // inherit less intense verbose, debug options
21797 for (int i = 1; i < algo_lib::_db.cmdline.verbose; i++) {
21798 ret << " -verbose";
21799 }
21800 for (int i = 1; i < algo_lib::_db.cmdline.debug; i++) {
21801 ret << " -debug";
21802 }
21803 return ret;
21804}
21805
21806// --- command.mdbg..PrintArgv
21807// print string representation of ROW to string STR
21808// cfmt:command.mdbg.Argv printfmt:Auto
21809void command::mdbg_PrintArgv(command::mdbg& row, algo::cstring& str) {
21810 algo::tempstr temp;
21811 (void)temp;
21812 (void)str;
21813 ch_RemoveAll(temp);
21814 Smallstr16_Print(row.target, temp);
21815 str << " -target:";
21816 strptr_PrintBash(temp,str);
21817 if (!(row.in == "data")) {
21818 ch_RemoveAll(temp);
21819 cstring_Print(row.in, temp);
21820 str << " -in:";
21821 strptr_PrintBash(temp,str);
21822 }
21823 ind_beg(mdbg_args_curs,value,row) {
21824 ch_RemoveAll(temp);
21825 cstring_Print(value, temp);
21826 str << " -args:";
21827 strptr_PrintBash(temp,str);
21828 }ind_end;
21829 if (!(row.cfg == "debug")) {
21830 ch_RemoveAll(temp);
21831 Smallstr50_Print(row.cfg, temp);
21832 str << " -cfg:";
21833 strptr_PrintBash(temp,str);
21834 }
21835 if (!(row.disas == false)) {
21836 ch_RemoveAll(temp);
21837 bool_Print(row.disas, temp);
21838 str << " -disas:";
21839 strptr_PrintBash(temp,str);
21840 }
21841 if (!(row.attach == false)) {
21842 ch_RemoveAll(temp);
21843 bool_Print(row.attach, temp);
21844 str << " -attach:";
21845 strptr_PrintBash(temp,str);
21846 }
21847 ind_beg(mdbg_b_curs,value,row) {
21848 ch_RemoveAll(temp);
21849 cstring_Print(value, temp);
21850 str << " -b:";
21851 strptr_PrintBash(temp,str);
21852 }ind_end;
21853 if (!(row.catchthrow == true)) {
21854 ch_RemoveAll(temp);
21855 bool_Print(row.catchthrow, temp);
21856 str << " -catchthrow:";
21857 strptr_PrintBash(temp,str);
21858 }
21859 if (!(row.tui == false)) {
21860 ch_RemoveAll(temp);
21861 bool_Print(row.tui, temp);
21862 str << " -tui:";
21863 strptr_PrintBash(temp,str);
21864 }
21865 if (!(row.bcmd == "")) {
21866 ch_RemoveAll(temp);
21867 cstring_Print(row.bcmd, temp);
21868 str << " -bcmd:";
21869 strptr_PrintBash(temp,str);
21870 }
21871 if (!(row.emacs == true)) {
21872 ch_RemoveAll(temp);
21873 bool_Print(row.emacs, temp);
21874 str << " -emacs:";
21875 strptr_PrintBash(temp,str);
21876 }
21877 if (!(row.manywin == false)) {
21878 ch_RemoveAll(temp);
21879 bool_Print(row.manywin, temp);
21880 str << " -manywin:";
21881 strptr_PrintBash(temp,str);
21882 }
21883 if (!(row.follow_child == false)) {
21884 ch_RemoveAll(temp);
21885 bool_Print(row.follow_child, temp);
21886 str << " -follow_child:";
21887 strptr_PrintBash(temp,str);
21888 }
21889 if (!(row.py == false)) {
21890 ch_RemoveAll(temp);
21891 bool_Print(row.py, temp);
21892 str << " -py:";
21893 strptr_PrintBash(temp,str);
21894 }
21895 if (!(row.dry_run == false)) {
21896 ch_RemoveAll(temp);
21897 bool_Print(row.dry_run, temp);
21898 str << " -dry_run:";
21899 strptr_PrintBash(temp,str);
21900 }
21901}
21902
21903// --- command.mdbg..GetAnon
21904algo::strptr command::mdbg_GetAnon(command::mdbg &parent, i32 idx) {
21905 (void)parent;//only to avoid -Wunused-parameter
21906 switch(idx) {
21907 case(0): return strptr("target", 6);
21908 default: return strptr("args", 4);
21909 }
21910}
21911
21912// --- command.mdbg..NArgs
21913// Used with command lines
21914// Return # of command-line arguments that must follow this argument
21915// If FIELD is invalid, return -1
21916i32 command::mdbg_NArgs(command::FieldId field, algo::strptr& out_dflt, bool* out_anon) {
21917 i32 retval = 1;
21918 switch (field) {
21919 case command_FieldId_target: { // $comment
21920 *out_anon = true;
21921 } break;
21922 case command_FieldId_in: { // $comment
21923 *out_anon = false;
21924 } break;
21925 case command_FieldId_args: { // $comment
21926 *out_anon = true;
21927 } break;
21928 case command_FieldId_cfg: { // $comment
21929 *out_anon = false;
21930 } break;
21931 case command_FieldId_disas: { // $comment
21932 *out_anon = false;
21933 retval=0;
21934 out_dflt="Y";
21935 } break;
21936 case command_FieldId_attach: { // bool: no argument required but value may be specified as disas:Y
21937 *out_anon = false;
21938 retval=0;
21939 out_dflt="Y";
21940 } break;
21941 case command_FieldId_b: { // bool: no argument required but value may be specified as attach:Y
21942 *out_anon = false;
21943 } break;
21944 case command_FieldId_catchthrow: { // bool: no argument required but value may be specified as attach:Y
21945 *out_anon = false;
21946 retval=0;
21947 out_dflt="Y";
21948 } break;
21949 case command_FieldId_tui: { // bool: no argument required but value may be specified as catchthrow:Y
21950 *out_anon = false;
21951 retval=0;
21952 out_dflt="Y";
21953 } break;
21954 case command_FieldId_bcmd: { // bool: no argument required but value may be specified as tui:Y
21955 *out_anon = false;
21956 } break;
21957 case command_FieldId_emacs: { // bool: no argument required but value may be specified as tui:Y
21958 *out_anon = false;
21959 retval=0;
21960 out_dflt="Y";
21961 } break;
21962 case command_FieldId_manywin: { // bool: no argument required but value may be specified as emacs:Y
21963 *out_anon = false;
21964 retval=0;
21965 out_dflt="Y";
21966 } break;
21967 case command_FieldId_follow_child: { // bool: no argument required but value may be specified as manywin:Y
21968 *out_anon = false;
21969 retval=0;
21970 out_dflt="Y";
21971 } break;
21972 case command_FieldId_py: { // bool: no argument required but value may be specified as follow_child:Y
21973 *out_anon = false;
21974 retval=0;
21975 out_dflt="Y";
21976 } break;
21977 case command_FieldId_dry_run: { // bool: no argument required but value may be specified as py:Y
21978 *out_anon = false;
21979 retval=0;
21980 out_dflt="Y";
21981 } break;
21982 default:
21983 retval=-1; // unrecognized
21984 }
21985 return retval;
21986}
21987
21988// --- command.mdbg_proc.mdbg.Start
21989// Start subprocess
21990// If subprocess already running, do nothing. Otherwise, start it
21991int command::mdbg_Start(command::mdbg_proc& parent) {
21992 int retval = 0;
21993 if (parent.pid == 0) {
21994 verblog(mdbg_ToCmdline(parent)); // maybe print command
21995#ifdef WIN32
21996 algo_lib::ResolveExecFname(parent.path);
21997 tempstr cmdline(mdbg_ToCmdline(parent));
21998 parent.pid = dospawn(Zeroterm(parent.path),Zeroterm(cmdline),parent.timeout,parent.fstdin,parent.fstdout,parent.fstderr);
21999#else
22000 parent.pid = fork();
22001 if (parent.pid == 0) { // child
22002 algo_lib::DieWithParent();
22003 if (parent.timeout > 0) {
22004 alarm(parent.timeout);
22005 }
22006 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstdin , 0);
22007 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstdout, 1);
22008 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstderr, 2);
22009 if (retval==0) retval= mdbg_Execv(parent);
22010 if (retval != 0) { // if start fails, print error
22011 int err=errno;
22012 prerr("command.mdbg_execv"
22013 <<Keyval("errno",err)
22014 <<Keyval("errstr",strerror(err))
22015 <<Keyval("comment","Execv failed"));
22016 }
22017 _exit(127); // if failed to start, exit anyway
22018 } else if (parent.pid == -1) {
22019 retval = errno; // failed to fork
22020 }
22021#endif
22022 }
22023 parent.status = parent.pid > 0 ? 0 : -1; // if didn't start, set error status
22024 return retval;
22025}
22026
22027// --- command.mdbg_proc.mdbg.StartRead
22028// Start subprocess & Read output
22029algo::Fildes command::mdbg_StartRead(command::mdbg_proc& parent, algo_lib::FFildes &read) {
22030 int pipefd[2];
22031 int rc=pipe(pipefd);
22032 (void)rc;
22033 read.fd.value = pipefd[0];
22034 parent.fstdout << ">&" << pipefd[1];
22035 mdbg_Start(parent);
22036 (void)close(pipefd[1]);
22037 return read.fd;
22038}
22039
22040// --- command.mdbg_proc.mdbg.Kill
22041// Kill subprocess and wait
22042void command::mdbg_Kill(command::mdbg_proc& parent) {
22043 if (parent.pid != 0) {
22044 kill(parent.pid,9);
22045 mdbg_Wait(parent);
22046 }
22047}
22048
22049// --- command.mdbg_proc.mdbg.Wait
22050// Wait for subprocess to return
22051void command::mdbg_Wait(command::mdbg_proc& parent) {
22052 if (parent.pid > 0) {
22053 int wait_flags = 0;
22054 int wait_status = 0;
22055 int rc = -1;
22056 do {
22057 // really wait for subprocess to exit
22058 rc = waitpid(parent.pid,&wait_status,wait_flags);
22059 } while (rc==-1 && errno==EINTR);
22060 if (rc == parent.pid) {
22061 parent.status = wait_status;
22062 parent.pid = 0;
22063 }
22064 }
22065}
22066
22067// --- command.mdbg_proc.mdbg.Exec
22068// Start + Wait
22069// Execute subprocess and return exit code
22070int command::mdbg_Exec(command::mdbg_proc& parent) {
22071 mdbg_Start(parent);
22072 mdbg_Wait(parent);
22073 return parent.status;
22074}
22075
22076// --- command.mdbg_proc.mdbg.ExecX
22077// Start + Wait, throw exception on error
22078// Execute subprocess; throw human-readable exception on error
22079void command::mdbg_ExecX(command::mdbg_proc& parent) {
22080 int rc = mdbg_Exec(parent);
22081 vrfy(rc==0, tempstr() << "algo_lib.exec" << Keyval("cmd",mdbg_ToCmdline(parent))
22082 << Keyval("comment",algo::DescribeWaitStatus(parent.status)));
22083}
22084
22085// --- command.mdbg_proc.mdbg.Execv
22086// Call execv()
22087// Call execv with specified parameters
22088int command::mdbg_Execv(command::mdbg_proc& parent) {
22089 int ret = 0;
22090 algo::StringAry args;
22091 mdbg_ToArgv(parent, args);
22092 char **argv = (char**)alloca((ary_N(args)+1)*sizeof(*argv));
22093 ind_beg(algo::StringAry_ary_curs,arg,args) {
22094 argv[ind_curs(arg).index] = Zeroterm(arg);
22095 }ind_end;
22096 argv[ary_N(args)] = NULL;
22097 // if parent.path is relative, search for it in PATH
22098 algo_lib::ResolveExecFname(parent.path);
22099 ret = execv(Zeroterm(parent.path),argv);
22100 return ret;
22101}
22102
22103// --- command.mdbg_proc.mdbg.ToCmdline
22104algo::tempstr command::mdbg_ToCmdline(command::mdbg_proc& parent) {
22105 algo::tempstr retval;
22106 retval << parent.path << " ";
22107 command::mdbg_PrintArgv(parent.cmd,retval);
22108 if (ch_N(parent.fstdin)) {
22109 retval << " " << parent.fstdin;
22110 }
22111 if (ch_N(parent.fstdout)) {
22112 retval << " " << parent.fstdout;
22113 }
22114 if (ch_N(parent.fstderr)) {
22115 retval << " 2" << parent.fstderr;
22116 }
22117 return retval;
22118}
22119
22120// --- command.mdbg_proc.mdbg.ToArgv
22121// Form array from the command line
22122void command::mdbg_ToArgv(command::mdbg_proc& parent, algo::StringAry& args) {
22123 ary_RemoveAll(args);
22124 ary_Alloc(args) << parent.path;
22125
22126 if (true) {
22127 cstring *arg = &ary_Alloc(args);
22128 *arg << "-target:";
22129 Smallstr16_Print(parent.cmd.target, *arg);
22130 }
22131
22132 if (parent.cmd.in != "data") {
22133 cstring *arg = &ary_Alloc(args);
22134 *arg << "-in:";
22135 cstring_Print(parent.cmd.in, *arg);
22136 }
22137 ind_beg(command::mdbg_args_curs,value,parent.cmd) {
22138 cstring *arg = &ary_Alloc(args);
22139 *arg << "-args:";
22140 cstring_Print(value, *arg);
22141 }ind_end;
22142
22143 if (parent.cmd.cfg != "debug") {
22144 cstring *arg = &ary_Alloc(args);
22145 *arg << "-cfg:";
22146 Smallstr50_Print(parent.cmd.cfg, *arg);
22147 }
22148
22149 if (parent.cmd.disas != false) {
22150 cstring *arg = &ary_Alloc(args);
22151 *arg << "-disas:";
22152 bool_Print(parent.cmd.disas, *arg);
22153 }
22154
22155 if (parent.cmd.attach != false) {
22156 cstring *arg = &ary_Alloc(args);
22157 *arg << "-attach:";
22158 bool_Print(parent.cmd.attach, *arg);
22159 }
22160 ind_beg(command::mdbg_b_curs,value,parent.cmd) {
22161 cstring *arg = &ary_Alloc(args);
22162 *arg << "-b:";
22163 cstring_Print(value, *arg);
22164 }ind_end;
22165
22166 if (parent.cmd.catchthrow != true) {
22167 cstring *arg = &ary_Alloc(args);
22168 *arg << "-catchthrow:";
22169 bool_Print(parent.cmd.catchthrow, *arg);
22170 }
22171
22172 if (parent.cmd.tui != false) {
22173 cstring *arg = &ary_Alloc(args);
22174 *arg << "-tui:";
22175 bool_Print(parent.cmd.tui, *arg);
22176 }
22177
22178 if (parent.cmd.bcmd != "") {
22179 cstring *arg = &ary_Alloc(args);
22180 *arg << "-bcmd:";
22181 cstring_Print(parent.cmd.bcmd, *arg);
22182 }
22183
22184 if (parent.cmd.emacs != true) {
22185 cstring *arg = &ary_Alloc(args);
22186 *arg << "-emacs:";
22187 bool_Print(parent.cmd.emacs, *arg);
22188 }
22189
22190 if (parent.cmd.manywin != false) {
22191 cstring *arg = &ary_Alloc(args);
22192 *arg << "-manywin:";
22193 bool_Print(parent.cmd.manywin, *arg);
22194 }
22195
22196 if (parent.cmd.follow_child != false) {
22197 cstring *arg = &ary_Alloc(args);
22198 *arg << "-follow_child:";
22199 bool_Print(parent.cmd.follow_child, *arg);
22200 }
22201
22202 if (parent.cmd.py != false) {
22203 cstring *arg = &ary_Alloc(args);
22204 *arg << "-py:";
22205 bool_Print(parent.cmd.py, *arg);
22206 }
22207
22208 if (parent.cmd.dry_run != false) {
22209 cstring *arg = &ary_Alloc(args);
22210 *arg << "-dry_run:";
22211 bool_Print(parent.cmd.dry_run, *arg);
22212 }
22213 for (int i=1; i < algo_lib::_db.cmdline.verbose; ++i) {
22214 ary_Alloc(args) << "-verbose";
22215 }
22216}
22217
22218// --- command.mdbg_proc..Uninit
22219void command::mdbg_proc_Uninit(command::mdbg_proc& parent) {
22220 command::mdbg_proc &row = parent; (void)row;
22221
22222 // command.mdbg_proc.mdbg.Uninit (Exec) //
22223 mdbg_Kill(parent); // kill child, ensure forward progress
22224}
22225
22226// --- command.mysql2ssim..ReadFieldMaybe
22227bool command::mysql2ssim_ReadFieldMaybe(command::mysql2ssim& parent, algo::strptr field, algo::strptr strval) {
22228 bool retval = true;
22229 command::FieldId field_id;
22230 (void)value_SetStrptrMaybe(field_id,field);
22231 switch(field_id) {
22232 case command_FieldId_writessimfile: {
22233 retval = bool_ReadStrptrMaybe(parent.writessimfile, strval);
22234 break;
22235 }
22236 case command_FieldId_url: {
22237 retval = algo::cstring_ReadStrptrMaybe(parent.url, strval);
22238 break;
22239 }
22240 case command_FieldId_tables: {
22241 retval = algo::cstring_ReadStrptrMaybe(parent.tables, strval);
22242 break;
22243 }
22244 case command_FieldId_schema: {
22245 retval = bool_ReadStrptrMaybe(parent.schema, strval);
22246 break;
22247 }
22248 case command_FieldId_in: {
22249 retval = algo::cstring_ReadStrptrMaybe(parent.in, strval);
22250 break;
22251 }
22252 case command_FieldId_pretty: {
22253 retval = bool_ReadStrptrMaybe(parent.pretty, strval);
22254 break;
22255 }
22256 case command_FieldId_nologo: {
22257 retval = bool_ReadStrptrMaybe(parent.nologo, strval);
22258 break;
22259 }
22260 case command_FieldId_baddbok: {
22261 retval = bool_ReadStrptrMaybe(parent.baddbok, strval);
22262 break;
22263 }
22264 default: break;
22265 }
22266 if (!retval) {
22267 algo_lib::AppendErrtext("attr",field);
22268 }
22269 return retval;
22270}
22271
22272// --- command.mysql2ssim..ReadTupleMaybe
22273// Read fields of command::mysql2ssim from attributes of ascii tuple TUPLE
22274bool command::mysql2ssim_ReadTupleMaybe(command::mysql2ssim &parent, algo::Tuple &tuple) {
22275 bool retval = true;
22276 int anon_idx = 0;
22277 ind_beg(algo::Tuple_attrs_curs,attr,tuple) {
22278 if (ch_N(attr.name) == 0) {
22279 attr.name = mysql2ssim_GetAnon(parent, anon_idx++);
22280 }
22281 retval = mysql2ssim_ReadFieldMaybe(parent, attr.name, attr.value);
22282 if (!retval) {
22283 break;
22284 }
22285 }ind_end;
22286 return retval;
22287}
22288
22289// --- command.mysql2ssim..ToCmdline
22290// Convenience function that returns a full command line
22291// Assume command is in a directory called bin
22292tempstr command::mysql2ssim_ToCmdline(command::mysql2ssim& row) {
22293 tempstr ret;
22294 ret << "bin/mysql2ssim ";
22295 mysql2ssim_PrintArgv(row, ret);
22296 // inherit less intense verbose, debug options
22297 for (int i = 1; i < algo_lib::_db.cmdline.verbose; i++) {
22298 ret << " -verbose";
22299 }
22300 for (int i = 1; i < algo_lib::_db.cmdline.debug; i++) {
22301 ret << " -debug";
22302 }
22303 return ret;
22304}
22305
22306// --- command.mysql2ssim..PrintArgv
22307// print string representation of ROW to string STR
22308// cfmt:command.mysql2ssim.Argv printfmt:Auto
22309void command::mysql2ssim_PrintArgv(command::mysql2ssim& row, algo::cstring& str) {
22310 algo::tempstr temp;
22311 (void)temp;
22312 (void)str;
22313 if (!(row.writessimfile == false)) {
22314 ch_RemoveAll(temp);
22315 bool_Print(row.writessimfile, temp);
22316 str << " -writessimfile:";
22317 strptr_PrintBash(temp,str);
22318 }
22319 ch_RemoveAll(temp);
22320 cstring_Print(row.url, temp);
22321 str << " -url:";
22322 strptr_PrintBash(temp,str);
22323 ch_RemoveAll(temp);
22324 cstring_Print(row.tables, temp);
22325 str << " -tables:";
22326 strptr_PrintBash(temp,str);
22327 if (!(row.schema == false)) {
22328 ch_RemoveAll(temp);
22329 bool_Print(row.schema, temp);
22330 str << " -schema:";
22331 strptr_PrintBash(temp,str);
22332 }
22333 if (!(row.in == "data")) {
22334 ch_RemoveAll(temp);
22335 cstring_Print(row.in, temp);
22336 str << " -in:";
22337 strptr_PrintBash(temp,str);
22338 }
22339 if (!(row.pretty == false)) {
22340 ch_RemoveAll(temp);
22341 bool_Print(row.pretty, temp);
22342 str << " -pretty:";
22343 strptr_PrintBash(temp,str);
22344 }
22345 if (!(row.nologo == false)) {
22346 ch_RemoveAll(temp);
22347 bool_Print(row.nologo, temp);
22348 str << " -nologo:";
22349 strptr_PrintBash(temp,str);
22350 }
22351 if (!(row.baddbok == false)) {
22352 ch_RemoveAll(temp);
22353 bool_Print(row.baddbok, temp);
22354 str << " -baddbok:";
22355 strptr_PrintBash(temp,str);
22356 }
22357}
22358
22359// --- command.mysql2ssim..GetAnon
22360algo::strptr command::mysql2ssim_GetAnon(command::mysql2ssim &parent, i32 idx) {
22361 (void)parent;//only to avoid -Wunused-parameter
22362 switch(idx) {
22363 case(0): return strptr("url", 3);
22364 case(1): return strptr("tables", 6);
22365 default: return algo::strptr();
22366 }
22367}
22368
22369// --- command.mysql2ssim..NArgs
22370// Used with command lines
22371// Return # of command-line arguments that must follow this argument
22372// If FIELD is invalid, return -1
22373i32 command::mysql2ssim_NArgs(command::FieldId field, algo::strptr& out_dflt, bool* out_anon) {
22374 i32 retval = 1;
22375 switch (field) {
22376 case command_FieldId_writessimfile: { // $comment
22377 *out_anon = false;
22378 retval=0;
22379 out_dflt="Y";
22380 } break;
22381 case command_FieldId_url: { // bool: no argument required but value may be specified as writessimfile:Y
22382 *out_anon = true;
22383 } break;
22384 case command_FieldId_tables: { // bool: no argument required but value may be specified as writessimfile:Y
22385 *out_anon = true;
22386 } break;
22387 case command_FieldId_schema: { // bool: no argument required but value may be specified as writessimfile:Y
22388 *out_anon = false;
22389 retval=0;
22390 out_dflt="Y";
22391 } break;
22392 case command_FieldId_in: { // bool: no argument required but value may be specified as schema:Y
22393 *out_anon = false;
22394 } break;
22395 case command_FieldId_pretty: { // bool: no argument required but value may be specified as schema:Y
22396 *out_anon = false;
22397 retval=0;
22398 out_dflt="Y";
22399 } break;
22400 case command_FieldId_nologo: { // bool: no argument required but value may be specified as pretty:Y
22401 *out_anon = false;
22402 retval=0;
22403 out_dflt="Y";
22404 } break;
22405 case command_FieldId_baddbok: { // bool: no argument required but value may be specified as nologo:Y
22406 *out_anon = false;
22407 retval=0;
22408 out_dflt="Y";
22409 } break;
22410 default:
22411 retval=-1; // unrecognized
22412 }
22413 return retval;
22414}
22415
22416// --- command.mysql2ssim_proc.mysql2ssim.Start
22417// Start subprocess
22418// If subprocess already running, do nothing. Otherwise, start it
22419int command::mysql2ssim_Start(command::mysql2ssim_proc& parent) {
22420 int retval = 0;
22421 if (parent.pid == 0) {
22422 verblog(mysql2ssim_ToCmdline(parent)); // maybe print command
22423#ifdef WIN32
22424 algo_lib::ResolveExecFname(parent.path);
22425 tempstr cmdline(mysql2ssim_ToCmdline(parent));
22426 parent.pid = dospawn(Zeroterm(parent.path),Zeroterm(cmdline),parent.timeout,parent.fstdin,parent.fstdout,parent.fstderr);
22427#else
22428 parent.pid = fork();
22429 if (parent.pid == 0) { // child
22430 algo_lib::DieWithParent();
22431 if (parent.timeout > 0) {
22432 alarm(parent.timeout);
22433 }
22434 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstdin , 0);
22435 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstdout, 1);
22436 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstderr, 2);
22437 if (retval==0) retval= mysql2ssim_Execv(parent);
22438 if (retval != 0) { // if start fails, print error
22439 int err=errno;
22440 prerr("command.mysql2ssim_execv"
22441 <<Keyval("errno",err)
22442 <<Keyval("errstr",strerror(err))
22443 <<Keyval("comment","Execv failed"));
22444 }
22445 _exit(127); // if failed to start, exit anyway
22446 } else if (parent.pid == -1) {
22447 retval = errno; // failed to fork
22448 }
22449#endif
22450 }
22451 parent.status = parent.pid > 0 ? 0 : -1; // if didn't start, set error status
22452 return retval;
22453}
22454
22455// --- command.mysql2ssim_proc.mysql2ssim.StartRead
22456// Start subprocess & Read output
22457algo::Fildes command::mysql2ssim_StartRead(command::mysql2ssim_proc& parent, algo_lib::FFildes &read) {
22458 int pipefd[2];
22459 int rc=pipe(pipefd);
22460 (void)rc;
22461 read.fd.value = pipefd[0];
22462 parent.fstdout << ">&" << pipefd[1];
22463 mysql2ssim_Start(parent);
22464 (void)close(pipefd[1]);
22465 return read.fd;
22466}
22467
22468// --- command.mysql2ssim_proc.mysql2ssim.Kill
22469// Kill subprocess and wait
22470void command::mysql2ssim_Kill(command::mysql2ssim_proc& parent) {
22471 if (parent.pid != 0) {
22472 kill(parent.pid,9);
22473 mysql2ssim_Wait(parent);
22474 }
22475}
22476
22477// --- command.mysql2ssim_proc.mysql2ssim.Wait
22478// Wait for subprocess to return
22479void command::mysql2ssim_Wait(command::mysql2ssim_proc& parent) {
22480 if (parent.pid > 0) {
22481 int wait_flags = 0;
22482 int wait_status = 0;
22483 int rc = -1;
22484 do {
22485 // really wait for subprocess to exit
22486 rc = waitpid(parent.pid,&wait_status,wait_flags);
22487 } while (rc==-1 && errno==EINTR);
22488 if (rc == parent.pid) {
22489 parent.status = wait_status;
22490 parent.pid = 0;
22491 }
22492 }
22493}
22494
22495// --- command.mysql2ssim_proc.mysql2ssim.Exec
22496// Start + Wait
22497// Execute subprocess and return exit code
22498int command::mysql2ssim_Exec(command::mysql2ssim_proc& parent) {
22499 mysql2ssim_Start(parent);
22500 mysql2ssim_Wait(parent);
22501 return parent.status;
22502}
22503
22504// --- command.mysql2ssim_proc.mysql2ssim.ExecX
22505// Start + Wait, throw exception on error
22506// Execute subprocess; throw human-readable exception on error
22507void command::mysql2ssim_ExecX(command::mysql2ssim_proc& parent) {
22508 int rc = mysql2ssim_Exec(parent);
22509 vrfy(rc==0, tempstr() << "algo_lib.exec" << Keyval("cmd",mysql2ssim_ToCmdline(parent))
22510 << Keyval("comment",algo::DescribeWaitStatus(parent.status)));
22511}
22512
22513// --- command.mysql2ssim_proc.mysql2ssim.Execv
22514// Call execv()
22515// Call execv with specified parameters
22516int command::mysql2ssim_Execv(command::mysql2ssim_proc& parent) {
22517 int ret = 0;
22518 algo::StringAry args;
22519 mysql2ssim_ToArgv(parent, args);
22520 char **argv = (char**)alloca((ary_N(args)+1)*sizeof(*argv));
22521 ind_beg(algo::StringAry_ary_curs,arg,args) {
22522 argv[ind_curs(arg).index] = Zeroterm(arg);
22523 }ind_end;
22524 argv[ary_N(args)] = NULL;
22525 // if parent.path is relative, search for it in PATH
22526 algo_lib::ResolveExecFname(parent.path);
22527 ret = execv(Zeroterm(parent.path),argv);
22528 return ret;
22529}
22530
22531// --- command.mysql2ssim_proc.mysql2ssim.ToCmdline
22532algo::tempstr command::mysql2ssim_ToCmdline(command::mysql2ssim_proc& parent) {
22533 algo::tempstr retval;
22534 retval << parent.path << " ";
22535 command::mysql2ssim_PrintArgv(parent.cmd,retval);
22536 if (ch_N(parent.fstdin)) {
22537 retval << " " << parent.fstdin;
22538 }
22539 if (ch_N(parent.fstdout)) {
22540 retval << " " << parent.fstdout;
22541 }
22542 if (ch_N(parent.fstderr)) {
22543 retval << " 2" << parent.fstderr;
22544 }
22545 return retval;
22546}
22547
22548// --- command.mysql2ssim_proc.mysql2ssim.ToArgv
22549// Form array from the command line
22550void command::mysql2ssim_ToArgv(command::mysql2ssim_proc& parent, algo::StringAry& args) {
22551 ary_RemoveAll(args);
22552 ary_Alloc(args) << parent.path;
22553
22554 if (parent.cmd.writessimfile != false) {
22555 cstring *arg = &ary_Alloc(args);
22556 *arg << "-writessimfile:";
22557 bool_Print(parent.cmd.writessimfile, *arg);
22558 }
22559
22560 if (true) {
22561 cstring *arg = &ary_Alloc(args);
22562 *arg << "-url:";
22563 cstring_Print(parent.cmd.url, *arg);
22564 }
22565
22566 if (parent.cmd.tables != "") {
22567 cstring *arg = &ary_Alloc(args);
22568 *arg << "-tables:";
22569 cstring_Print(parent.cmd.tables, *arg);
22570 }
22571
22572 if (parent.cmd.schema != false) {
22573 cstring *arg = &ary_Alloc(args);
22574 *arg << "-schema:";
22575 bool_Print(parent.cmd.schema, *arg);
22576 }
22577
22578 if (parent.cmd.in != "data") {
22579 cstring *arg = &ary_Alloc(args);
22580 *arg << "-in:";
22581 cstring_Print(parent.cmd.in, *arg);
22582 }
22583
22584 if (parent.cmd.pretty != false) {
22585 cstring *arg = &ary_Alloc(args);
22586 *arg << "-pretty:";
22587 bool_Print(parent.cmd.pretty, *arg);
22588 }
22589
22590 if (parent.cmd.nologo != false) {
22591 cstring *arg = &ary_Alloc(args);
22592 *arg << "-nologo:";
22593 bool_Print(parent.cmd.nologo, *arg);
22594 }
22595
22596 if (parent.cmd.baddbok != false) {
22597 cstring *arg = &ary_Alloc(args);
22598 *arg << "-baddbok:";
22599 bool_Print(parent.cmd.baddbok, *arg);
22600 }
22601 for (int i=1; i < algo_lib::_db.cmdline.verbose; ++i) {
22602 ary_Alloc(args) << "-verbose";
22603 }
22604}
22605
22606// --- command.mysql2ssim_proc..Uninit
22607void command::mysql2ssim_proc_Uninit(command::mysql2ssim_proc& parent) {
22608 command::mysql2ssim_proc &row = parent; (void)row;
22609
22610 // command.mysql2ssim_proc.mysql2ssim.Uninit (Exec) //
22611 mysql2ssim_Kill(parent); // kill child, ensure forward progress
22612}
22613
22614// --- command.orgfile.dedup.Print
22615// Print back to string
22616void command::dedup_Print(command::orgfile& parent, algo::cstring &out) {
22617 Regx_Print(parent.dedup, out);
22618}
22619
22620// --- command.orgfile.dedup.ReadStrptrMaybe
22621// Read Regx from string
22622// Convert string to field. Return success value
22623bool command::dedup_ReadStrptrMaybe(command::orgfile& parent, algo::strptr in) {
22624 bool retval = true;
22625 Regx_ReadSql(parent.dedup, in, true);
22626 return retval;
22627}
22628
22629// --- command.orgfile..ReadFieldMaybe
22630bool command::orgfile_ReadFieldMaybe(command::orgfile& parent, algo::strptr field, algo::strptr strval) {
22631 bool retval = true;
22632 command::FieldId field_id;
22633 (void)value_SetStrptrMaybe(field_id,field);
22634 switch(field_id) {
22635 case command_FieldId_in: {
22636 retval = algo::cstring_ReadStrptrMaybe(parent.in, strval);
22637 break;
22638 }
22639 case command_FieldId_move: {
22640 retval = algo::cstring_ReadStrptrMaybe(parent.move, strval);
22641 break;
22642 }
22643 case command_FieldId_dedup: {
22644 retval = dedup_ReadStrptrMaybe(parent, strval);
22645 break;
22646 }
22647 case command_FieldId_commit: {
22648 retval = bool_ReadStrptrMaybe(parent.commit, strval);
22649 break;
22650 }
22651 case command_FieldId_undo: {
22652 retval = bool_ReadStrptrMaybe(parent.undo, strval);
22653 break;
22654 }
22655 case command_FieldId_hash: {
22656 retval = algo::cstring_ReadStrptrMaybe(parent.hash, strval);
22657 break;
22658 }
22659 default: break;
22660 }
22661 if (!retval) {
22662 algo_lib::AppendErrtext("attr",field);
22663 }
22664 return retval;
22665}
22666
22667// --- command.orgfile..ReadTupleMaybe
22668// Read fields of command::orgfile from attributes of ascii tuple TUPLE
22669bool command::orgfile_ReadTupleMaybe(command::orgfile &parent, algo::Tuple &tuple) {
22670 bool retval = true;
22671 ind_beg(algo::Tuple_attrs_curs,attr,tuple) {
22672 retval = orgfile_ReadFieldMaybe(parent, attr.name, attr.value);
22673 if (!retval) {
22674 break;
22675 }
22676 }ind_end;
22677 return retval;
22678}
22679
22680// --- command.orgfile..Init
22681// Set all fields to initial values.
22682void command::orgfile_Init(command::orgfile& parent) {
22683 parent.in = algo::strptr("data");
22684 parent.move = algo::strptr("");
22685 Regx_ReadSql(parent.dedup, "", true);
22686 parent.commit = bool(false);
22687 parent.undo = bool(false);
22688 parent.hash = algo::strptr("sha1");
22689}
22690
22691// --- command.orgfile..ToCmdline
22692// Convenience function that returns a full command line
22693// Assume command is in a directory called bin
22694tempstr command::orgfile_ToCmdline(command::orgfile& row) {
22695 tempstr ret;
22696 ret << "bin/orgfile ";
22697 orgfile_PrintArgv(row, ret);
22698 // inherit less intense verbose, debug options
22699 for (int i = 1; i < algo_lib::_db.cmdline.verbose; i++) {
22700 ret << " -verbose";
22701 }
22702 for (int i = 1; i < algo_lib::_db.cmdline.debug; i++) {
22703 ret << " -debug";
22704 }
22705 return ret;
22706}
22707
22708// --- command.orgfile..PrintArgv
22709// print string representation of ROW to string STR
22710// cfmt:command.orgfile.Argv printfmt:Tuple
22711void command::orgfile_PrintArgv(command::orgfile& row, algo::cstring& str) {
22712 algo::tempstr temp;
22713 (void)temp;
22714 (void)str;
22715 if (!(row.in == "data")) {
22716 ch_RemoveAll(temp);
22717 cstring_Print(row.in, temp);
22718 str << " -in:";
22719 strptr_PrintBash(temp,str);
22720 }
22721 if (!(row.move == "")) {
22722 ch_RemoveAll(temp);
22723 cstring_Print(row.move, temp);
22724 str << " -move:";
22725 strptr_PrintBash(temp,str);
22726 }
22727 if (!(row.dedup.expr == "")) {
22728 ch_RemoveAll(temp);
22729 command::dedup_Print(const_cast<command::orgfile&>(row), temp);
22730 str << " -dedup:";
22731 strptr_PrintBash(temp,str);
22732 }
22733 if (!(row.commit == false)) {
22734 ch_RemoveAll(temp);
22735 bool_Print(row.commit, temp);
22736 str << " -commit:";
22737 strptr_PrintBash(temp,str);
22738 }
22739 if (!(row.undo == false)) {
22740 ch_RemoveAll(temp);
22741 bool_Print(row.undo, temp);
22742 str << " -undo:";
22743 strptr_PrintBash(temp,str);
22744 }
22745 if (!(row.hash == "sha1")) {
22746 ch_RemoveAll(temp);
22747 cstring_Print(row.hash, temp);
22748 str << " -hash:";
22749 strptr_PrintBash(temp,str);
22750 }
22751}
22752
22753// --- command.orgfile..NArgs
22754// Used with command lines
22755// Return # of command-line arguments that must follow this argument
22756// If FIELD is invalid, return -1
22757i32 command::orgfile_NArgs(command::FieldId field, algo::strptr& out_dflt, bool* out_anon) {
22758 i32 retval = 1;
22759 switch (field) {
22760 case command_FieldId_in: { // $comment
22761 *out_anon = false;
22762 } break;
22763 case command_FieldId_move: { // $comment
22764 *out_anon = false;
22765 } break;
22766 case command_FieldId_dedup: { // $comment
22767 *out_anon = false;
22768 } break;
22769 case command_FieldId_commit: { // $comment
22770 *out_anon = false;
22771 retval=0;
22772 out_dflt="Y";
22773 } break;
22774 case command_FieldId_undo: { // bool: no argument required but value may be specified as commit:Y
22775 *out_anon = false;
22776 retval=0;
22777 out_dflt="Y";
22778 } break;
22779 case command_FieldId_hash: { // bool: no argument required but value may be specified as undo:Y
22780 *out_anon = false;
22781 } break;
22782 default:
22783 retval=-1; // unrecognized
22784 }
22785 return retval;
22786}
22787
22788// --- command.orgfile_proc.orgfile.Start
22789// Start subprocess
22790// If subprocess already running, do nothing. Otherwise, start it
22791int command::orgfile_Start(command::orgfile_proc& parent) {
22792 int retval = 0;
22793 if (parent.pid == 0) {
22794 verblog(orgfile_ToCmdline(parent)); // maybe print command
22795#ifdef WIN32
22796 algo_lib::ResolveExecFname(parent.path);
22797 tempstr cmdline(orgfile_ToCmdline(parent));
22798 parent.pid = dospawn(Zeroterm(parent.path),Zeroterm(cmdline),parent.timeout,parent.fstdin,parent.fstdout,parent.fstderr);
22799#else
22800 parent.pid = fork();
22801 if (parent.pid == 0) { // child
22802 algo_lib::DieWithParent();
22803 if (parent.timeout > 0) {
22804 alarm(parent.timeout);
22805 }
22806 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstdin , 0);
22807 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstdout, 1);
22808 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstderr, 2);
22809 if (retval==0) retval= orgfile_Execv(parent);
22810 if (retval != 0) { // if start fails, print error
22811 int err=errno;
22812 prerr("command.orgfile_execv"
22813 <<Keyval("errno",err)
22814 <<Keyval("errstr",strerror(err))
22815 <<Keyval("comment","Execv failed"));
22816 }
22817 _exit(127); // if failed to start, exit anyway
22818 } else if (parent.pid == -1) {
22819 retval = errno; // failed to fork
22820 }
22821#endif
22822 }
22823 parent.status = parent.pid > 0 ? 0 : -1; // if didn't start, set error status
22824 return retval;
22825}
22826
22827// --- command.orgfile_proc.orgfile.StartRead
22828// Start subprocess & Read output
22829algo::Fildes command::orgfile_StartRead(command::orgfile_proc& parent, algo_lib::FFildes &read) {
22830 int pipefd[2];
22831 int rc=pipe(pipefd);
22832 (void)rc;
22833 read.fd.value = pipefd[0];
22834 parent.fstdout << ">&" << pipefd[1];
22835 orgfile_Start(parent);
22836 (void)close(pipefd[1]);
22837 return read.fd;
22838}
22839
22840// --- command.orgfile_proc.orgfile.Kill
22841// Kill subprocess and wait
22842void command::orgfile_Kill(command::orgfile_proc& parent) {
22843 if (parent.pid != 0) {
22844 kill(parent.pid,9);
22845 orgfile_Wait(parent);
22846 }
22847}
22848
22849// --- command.orgfile_proc.orgfile.Wait
22850// Wait for subprocess to return
22851void command::orgfile_Wait(command::orgfile_proc& parent) {
22852 if (parent.pid > 0) {
22853 int wait_flags = 0;
22854 int wait_status = 0;
22855 int rc = -1;
22856 do {
22857 // really wait for subprocess to exit
22858 rc = waitpid(parent.pid,&wait_status,wait_flags);
22859 } while (rc==-1 && errno==EINTR);
22860 if (rc == parent.pid) {
22861 parent.status = wait_status;
22862 parent.pid = 0;
22863 }
22864 }
22865}
22866
22867// --- command.orgfile_proc.orgfile.Exec
22868// Start + Wait
22869// Execute subprocess and return exit code
22870int command::orgfile_Exec(command::orgfile_proc& parent) {
22871 orgfile_Start(parent);
22872 orgfile_Wait(parent);
22873 return parent.status;
22874}
22875
22876// --- command.orgfile_proc.orgfile.ExecX
22877// Start + Wait, throw exception on error
22878// Execute subprocess; throw human-readable exception on error
22879void command::orgfile_ExecX(command::orgfile_proc& parent) {
22880 int rc = orgfile_Exec(parent);
22881 vrfy(rc==0, tempstr() << "algo_lib.exec" << Keyval("cmd",orgfile_ToCmdline(parent))
22882 << Keyval("comment",algo::DescribeWaitStatus(parent.status)));
22883}
22884
22885// --- command.orgfile_proc.orgfile.Execv
22886// Call execv()
22887// Call execv with specified parameters
22888int command::orgfile_Execv(command::orgfile_proc& parent) {
22889 int ret = 0;
22890 algo::StringAry args;
22891 orgfile_ToArgv(parent, args);
22892 char **argv = (char**)alloca((ary_N(args)+1)*sizeof(*argv));
22893 ind_beg(algo::StringAry_ary_curs,arg,args) {
22894 argv[ind_curs(arg).index] = Zeroterm(arg);
22895 }ind_end;
22896 argv[ary_N(args)] = NULL;
22897 // if parent.path is relative, search for it in PATH
22898 algo_lib::ResolveExecFname(parent.path);
22899 ret = execv(Zeroterm(parent.path),argv);
22900 return ret;
22901}
22902
22903// --- command.orgfile_proc.orgfile.ToCmdline
22904algo::tempstr command::orgfile_ToCmdline(command::orgfile_proc& parent) {
22905 algo::tempstr retval;
22906 retval << parent.path << " ";
22907 command::orgfile_PrintArgv(parent.cmd,retval);
22908 if (ch_N(parent.fstdin)) {
22909 retval << " " << parent.fstdin;
22910 }
22911 if (ch_N(parent.fstdout)) {
22912 retval << " " << parent.fstdout;
22913 }
22914 if (ch_N(parent.fstderr)) {
22915 retval << " 2" << parent.fstderr;
22916 }
22917 return retval;
22918}
22919
22920// --- command.orgfile_proc.orgfile.ToArgv
22921// Form array from the command line
22922void command::orgfile_ToArgv(command::orgfile_proc& parent, algo::StringAry& args) {
22923 ary_RemoveAll(args);
22924 ary_Alloc(args) << parent.path;
22925
22926 if (parent.cmd.in != "data") {
22927 cstring *arg = &ary_Alloc(args);
22928 *arg << "-in:";
22929 cstring_Print(parent.cmd.in, *arg);
22930 }
22931
22932 if (parent.cmd.move != "") {
22933 cstring *arg = &ary_Alloc(args);
22934 *arg << "-move:";
22935 cstring_Print(parent.cmd.move, *arg);
22936 }
22937
22938 if (parent.cmd.dedup.expr != "") {
22939 cstring *arg = &ary_Alloc(args);
22940 *arg << "-dedup:";
22941 command::dedup_Print(parent.cmd, *arg);
22942 }
22943
22944 if (parent.cmd.commit != false) {
22945 cstring *arg = &ary_Alloc(args);
22946 *arg << "-commit:";
22947 bool_Print(parent.cmd.commit, *arg);
22948 }
22949
22950 if (parent.cmd.undo != false) {
22951 cstring *arg = &ary_Alloc(args);
22952 *arg << "-undo:";
22953 bool_Print(parent.cmd.undo, *arg);
22954 }
22955
22956 if (parent.cmd.hash != "sha1") {
22957 cstring *arg = &ary_Alloc(args);
22958 *arg << "-hash:";
22959 cstring_Print(parent.cmd.hash, *arg);
22960 }
22961 for (int i=1; i < algo_lib::_db.cmdline.verbose; ++i) {
22962 ary_Alloc(args) << "-verbose";
22963 }
22964}
22965
22966// --- command.orgfile_proc..Uninit
22967void command::orgfile_proc_Uninit(command::orgfile_proc& parent) {
22968 command::orgfile_proc &row = parent; (void)row;
22969
22970 // command.orgfile_proc.orgfile.Uninit (Exec) //
22971 orgfile_Kill(parent); // kill child, ensure forward progress
22972}
22973
22974// --- command.samp_regx.style.ToCstr
22975// Convert numeric value of field to one of predefined string constants.
22976// If string is found, return a static C string. Otherwise, return NULL.
22977const char* command::style_ToCstr(const command::samp_regx& parent) {
22978 const char *ret = NULL;
22979 switch(style_GetEnum(parent)) {
22980 case command_samp_regx_style_acr : ret = "acr"; break;
22981 case command_samp_regx_style_shell : ret = "shell"; break;
22982 case command_samp_regx_style_classic: ret = "classic"; break;
22983 case command_samp_regx_style_literal: ret = "literal"; break;
22984 }
22985 return ret;
22986}
22987
22988// --- command.samp_regx.style.Print
22989// Convert style to a string. First, attempt conversion to a known string.
22990// If no string matches, print style as a numeric value.
22991void command::style_Print(const command::samp_regx& parent, algo::cstring &lhs) {
22992 const char *strval = style_ToCstr(parent);
22993 if (strval) {
22994 lhs << strval;
22995 } else {
22996 lhs << parent.style;
22997 }
22998}
22999
23000// --- command.samp_regx.style.SetStrptrMaybe
23001// Convert string to field.
23002// If the string is invalid, do not modify field and return false.
23003// In case of success, return true
23004bool command::style_SetStrptrMaybe(command::samp_regx& parent, algo::strptr rhs) {
23005 bool ret = false;
23006 switch (elems_N(rhs)) {
23007 case 3: {
23008 switch (u64(algo::ReadLE16(rhs.elems))|(u64(rhs[2])<<16)) {
23009 case LE_STR3('a','c','r'): {
23010 style_SetEnum(parent,command_samp_regx_style_acr); ret = true; break;
23011 }
23012 }
23013 break;
23014 }
23015 case 5: {
23016 switch (u64(algo::ReadLE32(rhs.elems))|(u64(rhs[4])<<32)) {
23017 case LE_STR5('s','h','e','l','l'): {
23018 style_SetEnum(parent,command_samp_regx_style_shell); ret = true; break;
23019 }
23020 }
23021 break;
23022 }
23023 case 7: {
23024 switch (u64(algo::ReadLE32(rhs.elems))|(u64(algo::ReadLE16(rhs.elems+4))<<32)|(u64(rhs[6])<<48)) {
23025 case LE_STR7('c','l','a','s','s','i','c'): {
23026 style_SetEnum(parent,command_samp_regx_style_classic); ret = true; break;
23027 }
23028 case LE_STR7('l','i','t','e','r','a','l'): {
23029 style_SetEnum(parent,command_samp_regx_style_literal); ret = true; break;
23030 }
23031 }
23032 break;
23033 }
23034 }
23035 return ret;
23036}
23037
23038// --- command.samp_regx.style.SetStrptr
23039// Convert string to field.
23040// If the string is invalid, set numeric value to DFLT
23041void command::style_SetStrptr(command::samp_regx& parent, algo::strptr rhs, command_samp_regx_style_Enum dflt) {
23042 if (!style_SetStrptrMaybe(parent,rhs)) style_SetEnum(parent,dflt);
23043}
23044
23045// --- command.samp_regx.style.ReadStrptrMaybe
23046// Convert string to field. Return success value
23047bool command::style_ReadStrptrMaybe(command::samp_regx& parent, algo::strptr rhs) {
23048 bool retval = false;
23049 retval = style_SetStrptrMaybe(parent,rhs); // try symbol conversion
23050 if (!retval) { // didn't work? try reading as underlying type
23051 retval = u8_ReadStrptrMaybe(parent.style,rhs);
23052 }
23053 return retval;
23054}
23055
23056// --- command.samp_regx..ReadFieldMaybe
23057bool command::samp_regx_ReadFieldMaybe(command::samp_regx& parent, algo::strptr field, algo::strptr strval) {
23058 bool retval = true;
23059 command::FieldId field_id;
23060 (void)value_SetStrptrMaybe(field_id,field);
23061 switch(field_id) {
23062 case command_FieldId_in: {
23063 retval = algo::cstring_ReadStrptrMaybe(parent.in, strval);
23064 break;
23065 }
23066 case command_FieldId_expr: {
23067 retval = algo::cstring_ReadStrptrMaybe(parent.expr, strval);
23068 break;
23069 }
23070 case command_FieldId_style: {
23071 retval = style_ReadStrptrMaybe(parent, strval);
23072 break;
23073 }
23074 case command_FieldId_match: {
23075 retval = bool_ReadStrptrMaybe(parent.match, strval);
23076 break;
23077 }
23078 case command_FieldId_string: {
23079 retval = algo::cstring_ReadStrptrMaybe(parent.string, strval);
23080 break;
23081 }
23082 case command_FieldId_show: {
23083 retval = bool_ReadStrptrMaybe(parent.show, strval);
23084 break;
23085 }
23086 default: break;
23087 }
23088 if (!retval) {
23089 algo_lib::AppendErrtext("attr",field);
23090 }
23091 return retval;
23092}
23093
23094// --- command.samp_regx..ReadTupleMaybe
23095// Read fields of command::samp_regx from attributes of ascii tuple TUPLE
23096bool command::samp_regx_ReadTupleMaybe(command::samp_regx &parent, algo::Tuple &tuple) {
23097 bool retval = true;
23098 int anon_idx = 0;
23099 ind_beg(algo::Tuple_attrs_curs,attr,tuple) {
23100 if (ch_N(attr.name) == 0) {
23101 attr.name = samp_regx_GetAnon(parent, anon_idx++);
23102 }
23103 retval = samp_regx_ReadFieldMaybe(parent, attr.name, attr.value);
23104 if (!retval) {
23105 break;
23106 }
23107 }ind_end;
23108 return retval;
23109}
23110
23111// --- command.samp_regx..ToCmdline
23112// Convenience function that returns a full command line
23113// Assume command is in a directory called bin
23114tempstr command::samp_regx_ToCmdline(command::samp_regx& row) {
23115 tempstr ret;
23116 ret << "bin/samp_regx ";
23117 samp_regx_PrintArgv(row, ret);
23118 // inherit less intense verbose, debug options
23119 for (int i = 1; i < algo_lib::_db.cmdline.verbose; i++) {
23120 ret << " -verbose";
23121 }
23122 for (int i = 1; i < algo_lib::_db.cmdline.debug; i++) {
23123 ret << " -debug";
23124 }
23125 return ret;
23126}
23127
23128// --- command.samp_regx..PrintArgv
23129// print string representation of ROW to string STR
23130// cfmt:command.samp_regx.Argv printfmt:Tuple
23131void command::samp_regx_PrintArgv(command::samp_regx& row, algo::cstring& str) {
23132 algo::tempstr temp;
23133 (void)temp;
23134 (void)str;
23135 if (!(row.in == "data")) {
23136 ch_RemoveAll(temp);
23137 cstring_Print(row.in, temp);
23138 str << " -in:";
23139 strptr_PrintBash(temp,str);
23140 }
23141 ch_RemoveAll(temp);
23142 cstring_Print(row.expr, temp);
23143 str << " -expr:";
23144 strptr_PrintBash(temp,str);
23145 if (!(row.style == 0)) {
23146 ch_RemoveAll(temp);
23147 command::style_Print(const_cast<command::samp_regx&>(row), temp);
23148 str << " -style:";
23149 strptr_PrintBash(temp,str);
23150 }
23151 if (!(row.match == false)) {
23152 ch_RemoveAll(temp);
23153 bool_Print(row.match, temp);
23154 str << " -match:";
23155 strptr_PrintBash(temp,str);
23156 }
23157 ch_RemoveAll(temp);
23158 cstring_Print(row.string, temp);
23159 str << " -string:";
23160 strptr_PrintBash(temp,str);
23161 if (!(row.show == false)) {
23162 ch_RemoveAll(temp);
23163 bool_Print(row.show, temp);
23164 str << " -show:";
23165 strptr_PrintBash(temp,str);
23166 }
23167}
23168
23169// --- command.samp_regx..GetAnon
23170algo::strptr command::samp_regx_GetAnon(command::samp_regx &parent, i32 idx) {
23171 (void)parent;//only to avoid -Wunused-parameter
23172 switch(idx) {
23173 case(0): return strptr("expr", 4);
23174 case(1): return strptr("string", 6);
23175 default: return algo::strptr();
23176 }
23177}
23178
23179// --- command.samp_regx..NArgs
23180// Used with command lines
23181// Return # of command-line arguments that must follow this argument
23182// If FIELD is invalid, return -1
23183i32 command::samp_regx_NArgs(command::FieldId field, algo::strptr& out_dflt, bool* out_anon) {
23184 i32 retval = 1;
23185 switch (field) {
23186 case command_FieldId_in: { // $comment
23187 *out_anon = false;
23188 } break;
23189 case command_FieldId_expr: { // $comment
23190 *out_anon = true;
23191 } break;
23192 case command_FieldId_style: { // $comment
23193 *out_anon = false;
23194 } break;
23195 case command_FieldId_match: { // $comment
23196 *out_anon = false;
23197 retval=0;
23198 out_dflt="Y";
23199 } break;
23200 case command_FieldId_string: { // bool: no argument required but value may be specified as match:Y
23201 *out_anon = true;
23202 } break;
23203 case command_FieldId_show: { // bool: no argument required but value may be specified as match:Y
23204 *out_anon = false;
23205 retval=0;
23206 out_dflt="Y";
23207 } break;
23208 default:
23209 retval=-1; // unrecognized
23210 }
23211 return retval;
23212}
23213
23214// --- command.samp_regx_proc.samp_regx.Start
23215// Start subprocess
23216// If subprocess already running, do nothing. Otherwise, start it
23217int command::samp_regx_Start(command::samp_regx_proc& parent) {
23218 int retval = 0;
23219 if (parent.pid == 0) {
23220 verblog(samp_regx_ToCmdline(parent)); // maybe print command
23221#ifdef WIN32
23222 algo_lib::ResolveExecFname(parent.path);
23223 tempstr cmdline(samp_regx_ToCmdline(parent));
23224 parent.pid = dospawn(Zeroterm(parent.path),Zeroterm(cmdline),parent.timeout,parent.fstdin,parent.fstdout,parent.fstderr);
23225#else
23226 parent.pid = fork();
23227 if (parent.pid == 0) { // child
23228 algo_lib::DieWithParent();
23229 if (parent.timeout > 0) {
23230 alarm(parent.timeout);
23231 }
23232 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstdin , 0);
23233 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstdout, 1);
23234 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstderr, 2);
23235 if (retval==0) retval= samp_regx_Execv(parent);
23236 if (retval != 0) { // if start fails, print error
23237 int err=errno;
23238 prerr("command.samp_regx_execv"
23239 <<Keyval("errno",err)
23240 <<Keyval("errstr",strerror(err))
23241 <<Keyval("comment","Execv failed"));
23242 }
23243 _exit(127); // if failed to start, exit anyway
23244 } else if (parent.pid == -1) {
23245 retval = errno; // failed to fork
23246 }
23247#endif
23248 }
23249 parent.status = parent.pid > 0 ? 0 : -1; // if didn't start, set error status
23250 return retval;
23251}
23252
23253// --- command.samp_regx_proc.samp_regx.StartRead
23254// Start subprocess & Read output
23255algo::Fildes command::samp_regx_StartRead(command::samp_regx_proc& parent, algo_lib::FFildes &read) {
23256 int pipefd[2];
23257 int rc=pipe(pipefd);
23258 (void)rc;
23259 read.fd.value = pipefd[0];
23260 parent.fstdout << ">&" << pipefd[1];
23261 samp_regx_Start(parent);
23262 (void)close(pipefd[1]);
23263 return read.fd;
23264}
23265
23266// --- command.samp_regx_proc.samp_regx.Kill
23267// Kill subprocess and wait
23268void command::samp_regx_Kill(command::samp_regx_proc& parent) {
23269 if (parent.pid != 0) {
23270 kill(parent.pid,9);
23271 samp_regx_Wait(parent);
23272 }
23273}
23274
23275// --- command.samp_regx_proc.samp_regx.Wait
23276// Wait for subprocess to return
23277void command::samp_regx_Wait(command::samp_regx_proc& parent) {
23278 if (parent.pid > 0) {
23279 int wait_flags = 0;
23280 int wait_status = 0;
23281 int rc = -1;
23282 do {
23283 // really wait for subprocess to exit
23284 rc = waitpid(parent.pid,&wait_status,wait_flags);
23285 } while (rc==-1 && errno==EINTR);
23286 if (rc == parent.pid) {
23287 parent.status = wait_status;
23288 parent.pid = 0;
23289 }
23290 }
23291}
23292
23293// --- command.samp_regx_proc.samp_regx.Exec
23294// Start + Wait
23295// Execute subprocess and return exit code
23296int command::samp_regx_Exec(command::samp_regx_proc& parent) {
23297 samp_regx_Start(parent);
23298 samp_regx_Wait(parent);
23299 return parent.status;
23300}
23301
23302// --- command.samp_regx_proc.samp_regx.ExecX
23303// Start + Wait, throw exception on error
23304// Execute subprocess; throw human-readable exception on error
23305void command::samp_regx_ExecX(command::samp_regx_proc& parent) {
23306 int rc = samp_regx_Exec(parent);
23307 vrfy(rc==0, tempstr() << "algo_lib.exec" << Keyval("cmd",samp_regx_ToCmdline(parent))
23308 << Keyval("comment",algo::DescribeWaitStatus(parent.status)));
23309}
23310
23311// --- command.samp_regx_proc.samp_regx.Execv
23312// Call execv()
23313// Call execv with specified parameters
23314int command::samp_regx_Execv(command::samp_regx_proc& parent) {
23315 int ret = 0;
23316 algo::StringAry args;
23317 samp_regx_ToArgv(parent, args);
23318 char **argv = (char**)alloca((ary_N(args)+1)*sizeof(*argv));
23319 ind_beg(algo::StringAry_ary_curs,arg,args) {
23320 argv[ind_curs(arg).index] = Zeroterm(arg);
23321 }ind_end;
23322 argv[ary_N(args)] = NULL;
23323 // if parent.path is relative, search for it in PATH
23324 algo_lib::ResolveExecFname(parent.path);
23325 ret = execv(Zeroterm(parent.path),argv);
23326 return ret;
23327}
23328
23329// --- command.samp_regx_proc.samp_regx.ToCmdline
23330algo::tempstr command::samp_regx_ToCmdline(command::samp_regx_proc& parent) {
23331 algo::tempstr retval;
23332 retval << parent.path << " ";
23333 command::samp_regx_PrintArgv(parent.cmd,retval);
23334 if (ch_N(parent.fstdin)) {
23335 retval << " " << parent.fstdin;
23336 }
23337 if (ch_N(parent.fstdout)) {
23338 retval << " " << parent.fstdout;
23339 }
23340 if (ch_N(parent.fstderr)) {
23341 retval << " 2" << parent.fstderr;
23342 }
23343 return retval;
23344}
23345
23346// --- command.samp_regx_proc.samp_regx.ToArgv
23347// Form array from the command line
23348void command::samp_regx_ToArgv(command::samp_regx_proc& parent, algo::StringAry& args) {
23349 ary_RemoveAll(args);
23350 ary_Alloc(args) << parent.path;
23351
23352 if (parent.cmd.in != "data") {
23353 cstring *arg = &ary_Alloc(args);
23354 *arg << "-in:";
23355 cstring_Print(parent.cmd.in, *arg);
23356 }
23357
23358 if (true) {
23359 cstring *arg = &ary_Alloc(args);
23360 *arg << "-expr:";
23361 cstring_Print(parent.cmd.expr, *arg);
23362 }
23363
23364 if (parent.cmd.style != 0) {
23365 cstring *arg = &ary_Alloc(args);
23366 *arg << "-style:";
23367 command::style_Print(parent.cmd, *arg);
23368 }
23369
23370 if (parent.cmd.match != false) {
23371 cstring *arg = &ary_Alloc(args);
23372 *arg << "-match:";
23373 bool_Print(parent.cmd.match, *arg);
23374 }
23375
23376 if (parent.cmd.string != "") {
23377 cstring *arg = &ary_Alloc(args);
23378 *arg << "-string:";
23379 cstring_Print(parent.cmd.string, *arg);
23380 }
23381
23382 if (parent.cmd.show != false) {
23383 cstring *arg = &ary_Alloc(args);
23384 *arg << "-show:";
23385 bool_Print(parent.cmd.show, *arg);
23386 }
23387 for (int i=1; i < algo_lib::_db.cmdline.verbose; ++i) {
23388 ary_Alloc(args) << "-verbose";
23389 }
23390}
23391
23392// --- command.samp_regx_proc..Uninit
23393void command::samp_regx_proc_Uninit(command::samp_regx_proc& parent) {
23394 command::samp_regx_proc &row = parent; (void)row;
23395
23396 // command.samp_regx_proc.samp_regx.Uninit (Exec) //
23397 samp_regx_Kill(parent); // kill child, ensure forward progress
23398}
23399
23400// --- command.samp_ws..ReadFieldMaybe
23401bool command::samp_ws_ReadFieldMaybe(command::samp_ws& parent, algo::strptr field, algo::strptr strval) {
23402 bool retval = true;
23403 command::FieldId field_id;
23404 (void)value_SetStrptrMaybe(field_id,field);
23405 switch(field_id) {
23406 case command_FieldId_in: {
23407 retval = algo::cstring_ReadStrptrMaybe(parent.in, strval);
23408 break;
23409 }
23410 default: break;
23411 }
23412 if (!retval) {
23413 algo_lib::AppendErrtext("attr",field);
23414 }
23415 return retval;
23416}
23417
23418// --- command.samp_ws..ReadTupleMaybe
23419// Read fields of command::samp_ws from attributes of ascii tuple TUPLE
23420bool command::samp_ws_ReadTupleMaybe(command::samp_ws &parent, algo::Tuple &tuple) {
23421 bool retval = true;
23422 ind_beg(algo::Tuple_attrs_curs,attr,tuple) {
23423 retval = samp_ws_ReadFieldMaybe(parent, attr.name, attr.value);
23424 if (!retval) {
23425 break;
23426 }
23427 }ind_end;
23428 return retval;
23429}
23430
23431// --- command.samp_ws..ToCmdline
23432// Convenience function that returns a full command line
23433// Assume command is in a directory called bin
23434tempstr command::samp_ws_ToCmdline(command::samp_ws& row) {
23435 tempstr ret;
23436 ret << "bin/samp_ws ";
23437 samp_ws_PrintArgv(row, ret);
23438 // inherit less intense verbose, debug options
23439 for (int i = 1; i < algo_lib::_db.cmdline.verbose; i++) {
23440 ret << " -verbose";
23441 }
23442 for (int i = 1; i < algo_lib::_db.cmdline.debug; i++) {
23443 ret << " -debug";
23444 }
23445 return ret;
23446}
23447
23448// --- command.samp_ws..PrintArgv
23449// print string representation of ROW to string STR
23450// cfmt:command.samp_ws.Argv printfmt:Tuple
23451void command::samp_ws_PrintArgv(command::samp_ws& row, algo::cstring& str) {
23452 algo::tempstr temp;
23453 (void)temp;
23454 (void)str;
23455 if (!(row.in == "data")) {
23456 ch_RemoveAll(temp);
23457 cstring_Print(row.in, temp);
23458 str << " -in:";
23459 strptr_PrintBash(temp,str);
23460 }
23461}
23462
23463// --- command.samp_ws..NArgs
23464// Used with command lines
23465// Return # of command-line arguments that must follow this argument
23466// If FIELD is invalid, return -1
23467i32 command::samp_ws_NArgs(command::FieldId field, algo::strptr& out_dflt, bool* out_anon) {
23468 i32 retval = 1;
23469 switch (field) {
23470 case command_FieldId_in: { // $comment
23471 *out_anon = false;
23472 } break;
23473 default:
23474 retval=-1; // unrecognized
23475 }
23476 (void)out_dflt;//only to avoid -Wunused-parameter
23477 return retval;
23478}
23479
23480// --- command.samp_ws_proc.samp_ws.Start
23481// Start subprocess
23482// If subprocess already running, do nothing. Otherwise, start it
23483int command::samp_ws_Start(command::samp_ws_proc& parent) {
23484 int retval = 0;
23485 if (parent.pid == 0) {
23486 verblog(samp_ws_ToCmdline(parent)); // maybe print command
23487#ifdef WIN32
23488 algo_lib::ResolveExecFname(parent.path);
23489 tempstr cmdline(samp_ws_ToCmdline(parent));
23490 parent.pid = dospawn(Zeroterm(parent.path),Zeroterm(cmdline),parent.timeout,parent.fstdin,parent.fstdout,parent.fstderr);
23491#else
23492 parent.pid = fork();
23493 if (parent.pid == 0) { // child
23494 algo_lib::DieWithParent();
23495 if (parent.timeout > 0) {
23496 alarm(parent.timeout);
23497 }
23498 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstdin , 0);
23499 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstdout, 1);
23500 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstderr, 2);
23501 if (retval==0) retval= samp_ws_Execv(parent);
23502 if (retval != 0) { // if start fails, print error
23503 int err=errno;
23504 prerr("command.samp_ws_execv"
23505 <<Keyval("errno",err)
23506 <<Keyval("errstr",strerror(err))
23507 <<Keyval("comment","Execv failed"));
23508 }
23509 _exit(127); // if failed to start, exit anyway
23510 } else if (parent.pid == -1) {
23511 retval = errno; // failed to fork
23512 }
23513#endif
23514 }
23515 parent.status = parent.pid > 0 ? 0 : -1; // if didn't start, set error status
23516 return retval;
23517}
23518
23519// --- command.samp_ws_proc.samp_ws.StartRead
23520// Start subprocess & Read output
23521algo::Fildes command::samp_ws_StartRead(command::samp_ws_proc& parent, algo_lib::FFildes &read) {
23522 int pipefd[2];
23523 int rc=pipe(pipefd);
23524 (void)rc;
23525 read.fd.value = pipefd[0];
23526 parent.fstdout << ">&" << pipefd[1];
23527 samp_ws_Start(parent);
23528 (void)close(pipefd[1]);
23529 return read.fd;
23530}
23531
23532// --- command.samp_ws_proc.samp_ws.Kill
23533// Kill subprocess and wait
23534void command::samp_ws_Kill(command::samp_ws_proc& parent) {
23535 if (parent.pid != 0) {
23536 kill(parent.pid,9);
23537 samp_ws_Wait(parent);
23538 }
23539}
23540
23541// --- command.samp_ws_proc.samp_ws.Wait
23542// Wait for subprocess to return
23543void command::samp_ws_Wait(command::samp_ws_proc& parent) {
23544 if (parent.pid > 0) {
23545 int wait_flags = 0;
23546 int wait_status = 0;
23547 int rc = -1;
23548 do {
23549 // really wait for subprocess to exit
23550 rc = waitpid(parent.pid,&wait_status,wait_flags);
23551 } while (rc==-1 && errno==EINTR);
23552 if (rc == parent.pid) {
23553 parent.status = wait_status;
23554 parent.pid = 0;
23555 }
23556 }
23557}
23558
23559// --- command.samp_ws_proc.samp_ws.Exec
23560// Start + Wait
23561// Execute subprocess and return exit code
23562int command::samp_ws_Exec(command::samp_ws_proc& parent) {
23563 samp_ws_Start(parent);
23564 samp_ws_Wait(parent);
23565 return parent.status;
23566}
23567
23568// --- command.samp_ws_proc.samp_ws.ExecX
23569// Start + Wait, throw exception on error
23570// Execute subprocess; throw human-readable exception on error
23571void command::samp_ws_ExecX(command::samp_ws_proc& parent) {
23572 int rc = samp_ws_Exec(parent);
23573 vrfy(rc==0, tempstr() << "algo_lib.exec" << Keyval("cmd",samp_ws_ToCmdline(parent))
23574 << Keyval("comment",algo::DescribeWaitStatus(parent.status)));
23575}
23576
23577// --- command.samp_ws_proc.samp_ws.Execv
23578// Call execv()
23579// Call execv with specified parameters
23580int command::samp_ws_Execv(command::samp_ws_proc& parent) {
23581 int ret = 0;
23582 algo::StringAry args;
23583 samp_ws_ToArgv(parent, args);
23584 char **argv = (char**)alloca((ary_N(args)+1)*sizeof(*argv));
23585 ind_beg(algo::StringAry_ary_curs,arg,args) {
23586 argv[ind_curs(arg).index] = Zeroterm(arg);
23587 }ind_end;
23588 argv[ary_N(args)] = NULL;
23589 // if parent.path is relative, search for it in PATH
23590 algo_lib::ResolveExecFname(parent.path);
23591 ret = execv(Zeroterm(parent.path),argv);
23592 return ret;
23593}
23594
23595// --- command.samp_ws_proc.samp_ws.ToCmdline
23596algo::tempstr command::samp_ws_ToCmdline(command::samp_ws_proc& parent) {
23597 algo::tempstr retval;
23598 retval << parent.path << " ";
23599 command::samp_ws_PrintArgv(parent.cmd,retval);
23600 if (ch_N(parent.fstdin)) {
23601 retval << " " << parent.fstdin;
23602 }
23603 if (ch_N(parent.fstdout)) {
23604 retval << " " << parent.fstdout;
23605 }
23606 if (ch_N(parent.fstderr)) {
23607 retval << " 2" << parent.fstderr;
23608 }
23609 return retval;
23610}
23611
23612// --- command.samp_ws_proc.samp_ws.ToArgv
23613// Form array from the command line
23614void command::samp_ws_ToArgv(command::samp_ws_proc& parent, algo::StringAry& args) {
23615 ary_RemoveAll(args);
23616 ary_Alloc(args) << parent.path;
23617
23618 if (parent.cmd.in != "data") {
23619 cstring *arg = &ary_Alloc(args);
23620 *arg << "-in:";
23621 cstring_Print(parent.cmd.in, *arg);
23622 }
23623 for (int i=1; i < algo_lib::_db.cmdline.verbose; ++i) {
23624 ary_Alloc(args) << "-verbose";
23625 }
23626}
23627
23628// --- command.samp_ws_proc..Uninit
23629void command::samp_ws_proc_Uninit(command::samp_ws_proc& parent) {
23630 command::samp_ws_proc &row = parent; (void)row;
23631
23632 // command.samp_ws_proc.samp_ws.Uninit (Exec) //
23633 samp_ws_Kill(parent); // kill child, ensure forward progress
23634}
23635
23636// --- command.sandbox.name.Print
23637// Print back to string
23638void command::name_Print(command::sandbox& parent, algo::cstring &out) {
23639 Regx_Print(parent.name, out);
23640}
23641
23642// --- command.sandbox.name.ReadStrptrMaybe
23643// Read Regx from string
23644// Convert string to field. Return success value
23645bool command::name_ReadStrptrMaybe(command::sandbox& parent, algo::strptr in) {
23646 bool retval = true;
23647 Regx_ReadSql(parent.name, in, true);
23648 return retval;
23649}
23650
23651// --- command.sandbox.cmd.Addary
23652// Reserve space (this may move memory). Insert N element at the end.
23653// Return aryptr to newly inserted block.
23654// If the RHS argument aliases the array (refers to the same memory), exit program with fatal error.
23655algo::aryptr<algo::cstring> command::cmd_Addary(command::sandbox& parent, algo::aryptr<algo::cstring> rhs) {
23656 bool overlaps = rhs.n_elems>0 && rhs.elems >= parent.cmd_elems && rhs.elems < parent.cmd_elems + parent.cmd_max;
23657 if (UNLIKELY(overlaps)) {
23658 FatalErrorExit("command.tary_alias field:command.sandbox.cmd comment:'alias error: sub-array is being appended to the whole'");
23659 }
23660 int nnew = rhs.n_elems;
23661 cmd_Reserve(parent, nnew); // reserve space
23662 int at = parent.cmd_n;
23663 for (int i = 0; i < nnew; i++) {
23664 new (parent.cmd_elems + at + i) algo::cstring(rhs[i]);
23665 parent.cmd_n++;
23666 }
23667 return algo::aryptr<algo::cstring>(parent.cmd_elems + at, nnew);
23668}
23669
23670// --- command.sandbox.cmd.Alloc
23671// Reserve space. Insert element at the end
23672// The new element is initialized to a default value
23673algo::cstring& command::cmd_Alloc(command::sandbox& parent) {
23674 cmd_Reserve(parent, 1);
23675 int n = parent.cmd_n;
23676 int at = n;
23677 algo::cstring *elems = parent.cmd_elems;
23678 new (elems + at) algo::cstring(); // construct new element, default initializer
23679 parent.cmd_n = n+1;
23680 return elems[at];
23681}
23682
23683// --- command.sandbox.cmd.AllocAt
23684// Reserve space for new element, reallocating the array if necessary
23685// Insert new element at specified index. Index must be in range or a fatal error occurs.
23686algo::cstring& command::cmd_AllocAt(command::sandbox& parent, int at) {
23687 cmd_Reserve(parent, 1);
23688 int n = parent.cmd_n;
23689 if (UNLIKELY(u64(at) >= u64(n+1))) {
23690 FatalErrorExit("command.bad_alloc_at field:command.sandbox.cmd comment:'index out of range'");
23691 }
23692 algo::cstring *elems = parent.cmd_elems;
23693 memmove(elems + at + 1, elems + at, (n - at) * sizeof(algo::cstring));
23694 new (elems + at) algo::cstring(); // construct element, default initializer
23695 parent.cmd_n = n+1;
23696 return elems[at];
23697}
23698
23699// --- command.sandbox.cmd.AllocN
23700// Reserve space. Insert N elements at the end of the array, return pointer to array
23701algo::aryptr<algo::cstring> command::cmd_AllocN(command::sandbox& parent, int n_elems) {
23702 cmd_Reserve(parent, n_elems);
23703 int old_n = parent.cmd_n;
23704 int new_n = old_n + n_elems;
23705 algo::cstring *elems = parent.cmd_elems;
23706 for (int i = old_n; i < new_n; i++) {
23707 new (elems + i) algo::cstring(); // construct new element, default initialize
23708 }
23709 parent.cmd_n = new_n;
23710 return algo::aryptr<algo::cstring>(elems + old_n, n_elems);
23711}
23712
23713// --- command.sandbox.cmd.Remove
23714// Remove item by index. If index outside of range, do nothing.
23715void command::cmd_Remove(command::sandbox& parent, u32 i) {
23716 u32 lim = parent.cmd_n;
23717 algo::cstring *elems = parent.cmd_elems;
23718 if (i < lim) {
23719 elems[i].~cstring(); // destroy element
23720 memmove(elems + i, elems + (i + 1), sizeof(algo::cstring) * (lim - (i + 1)));
23721 parent.cmd_n = lim - 1;
23722 }
23723}
23724
23725// --- command.sandbox.cmd.RemoveAll
23726void command::cmd_RemoveAll(command::sandbox& parent) {
23727 u32 n = parent.cmd_n;
23728 while (n > 0) {
23729 n -= 1;
23730 parent.cmd_elems[n].~cstring();
23731 parent.cmd_n = n;
23732 }
23733}
23734
23735// --- command.sandbox.cmd.RemoveLast
23736// Delete last element of array. Do nothing if array is empty.
23737void command::cmd_RemoveLast(command::sandbox& parent) {
23738 u64 n = parent.cmd_n;
23739 if (n > 0) {
23740 n -= 1;
23741 cmd_qFind(parent, u64(n)).~cstring();
23742 parent.cmd_n = n;
23743 }
23744}
23745
23746// --- command.sandbox.cmd.AbsReserve
23747// Make sure N elements fit in array. Process dies if out of memory
23748void command::cmd_AbsReserve(command::sandbox& parent, int n) {
23749 u32 old_max = parent.cmd_max;
23750 if (n > i32(old_max)) {
23751 u32 new_max = i32_Max(i32_Max(old_max * 2, n), 4);
23752 void *new_mem = algo_lib::malloc_ReallocMem(parent.cmd_elems, old_max * sizeof(algo::cstring), new_max * sizeof(algo::cstring));
23753 if (UNLIKELY(!new_mem)) {
23754 FatalErrorExit("command.tary_nomem field:command.sandbox.cmd comment:'out of memory'");
23755 }
23756 parent.cmd_elems = (algo::cstring*)new_mem;
23757 parent.cmd_max = new_max;
23758 }
23759}
23760
23761// --- command.sandbox.cmd.Setary
23762// Copy contents of RHS to PARENT.
23763void command::cmd_Setary(command::sandbox& parent, command::sandbox &rhs) {
23764 cmd_RemoveAll(parent);
23765 int nnew = rhs.cmd_n;
23766 cmd_Reserve(parent, nnew); // reserve space
23767 for (int i = 0; i < nnew; i++) { // copy elements over
23768 new (parent.cmd_elems + i) algo::cstring(cmd_qFind(rhs, i));
23769 parent.cmd_n = i + 1;
23770 }
23771}
23772
23773// --- command.sandbox.cmd.Setary2
23774// Copy specified array into cmd, discarding previous contents.
23775// If the RHS argument aliases the array (refers to the same memory), throw exception.
23776void command::cmd_Setary(command::sandbox& parent, const algo::aryptr<algo::cstring> &rhs) {
23777 cmd_RemoveAll(parent);
23778 cmd_Addary(parent, rhs);
23779}
23780
23781// --- command.sandbox.cmd.AllocNVal
23782// Reserve space. Insert N elements at the end of the array, return pointer to array
23783algo::aryptr<algo::cstring> command::cmd_AllocNVal(command::sandbox& parent, int n_elems, const algo::cstring& val) {
23784 cmd_Reserve(parent, n_elems);
23785 int old_n = parent.cmd_n;
23786 int new_n = old_n + n_elems;
23787 algo::cstring *elems = parent.cmd_elems;
23788 for (int i = old_n; i < new_n; i++) {
23789 new (elems + i) algo::cstring(val);
23790 }
23791 parent.cmd_n = new_n;
23792 return algo::aryptr<algo::cstring>(elems + old_n, n_elems);
23793}
23794
23795// --- command.sandbox.cmd.ReadStrptrMaybe
23796// A single element is read from input string and appended to the array.
23797// If the string contains an error, the array is untouched.
23798// Function returns success value.
23799bool command::cmd_ReadStrptrMaybe(command::sandbox& parent, algo::strptr in_str) {
23800 bool retval = true;
23801 algo::cstring &elem = cmd_Alloc(parent);
23802 retval = algo::cstring_ReadStrptrMaybe(elem, in_str);
23803 if (!retval) {
23804 cmd_RemoveLast(parent);
23805 }
23806 return retval;
23807}
23808
23809// --- command.sandbox.files.Addary
23810// Reserve space (this may move memory). Insert N element at the end.
23811// Return aryptr to newly inserted block.
23812// If the RHS argument aliases the array (refers to the same memory), exit program with fatal error.
23813algo::aryptr<algo::cstring> command::files_Addary(command::sandbox& parent, algo::aryptr<algo::cstring> rhs) {
23814 bool overlaps = rhs.n_elems>0 && rhs.elems >= parent.files_elems && rhs.elems < parent.files_elems + parent.files_max;
23815 if (UNLIKELY(overlaps)) {
23816 FatalErrorExit("command.tary_alias field:command.sandbox.files comment:'alias error: sub-array is being appended to the whole'");
23817 }
23818 int nnew = rhs.n_elems;
23819 files_Reserve(parent, nnew); // reserve space
23820 int at = parent.files_n;
23821 for (int i = 0; i < nnew; i++) {
23822 new (parent.files_elems + at + i) algo::cstring(rhs[i]);
23823 parent.files_n++;
23824 }
23825 return algo::aryptr<algo::cstring>(parent.files_elems + at, nnew);
23826}
23827
23828// --- command.sandbox.files.Alloc
23829// Reserve space. Insert element at the end
23830// The new element is initialized to a default value
23831algo::cstring& command::files_Alloc(command::sandbox& parent) {
23832 files_Reserve(parent, 1);
23833 int n = parent.files_n;
23834 int at = n;
23835 algo::cstring *elems = parent.files_elems;
23836 new (elems + at) algo::cstring(); // construct new element, default initializer
23837 parent.files_n = n+1;
23838 return elems[at];
23839}
23840
23841// --- command.sandbox.files.AllocAt
23842// Reserve space for new element, reallocating the array if necessary
23843// Insert new element at specified index. Index must be in range or a fatal error occurs.
23844algo::cstring& command::files_AllocAt(command::sandbox& parent, int at) {
23845 files_Reserve(parent, 1);
23846 int n = parent.files_n;
23847 if (UNLIKELY(u64(at) >= u64(n+1))) {
23848 FatalErrorExit("command.bad_alloc_at field:command.sandbox.files comment:'index out of range'");
23849 }
23850 algo::cstring *elems = parent.files_elems;
23851 memmove(elems + at + 1, elems + at, (n - at) * sizeof(algo::cstring));
23852 new (elems + at) algo::cstring(); // construct element, default initializer
23853 parent.files_n = n+1;
23854 return elems[at];
23855}
23856
23857// --- command.sandbox.files.AllocN
23858// Reserve space. Insert N elements at the end of the array, return pointer to array
23859algo::aryptr<algo::cstring> command::files_AllocN(command::sandbox& parent, int n_elems) {
23860 files_Reserve(parent, n_elems);
23861 int old_n = parent.files_n;
23862 int new_n = old_n + n_elems;
23863 algo::cstring *elems = parent.files_elems;
23864 for (int i = old_n; i < new_n; i++) {
23865 new (elems + i) algo::cstring(); // construct new element, default initialize
23866 }
23867 parent.files_n = new_n;
23868 return algo::aryptr<algo::cstring>(elems + old_n, n_elems);
23869}
23870
23871// --- command.sandbox.files.Remove
23872// Remove item by index. If index outside of range, do nothing.
23873void command::files_Remove(command::sandbox& parent, u32 i) {
23874 u32 lim = parent.files_n;
23875 algo::cstring *elems = parent.files_elems;
23876 if (i < lim) {
23877 elems[i].~cstring(); // destroy element
23878 memmove(elems + i, elems + (i + 1), sizeof(algo::cstring) * (lim - (i + 1)));
23879 parent.files_n = lim - 1;
23880 }
23881}
23882
23883// --- command.sandbox.files.RemoveAll
23884void command::files_RemoveAll(command::sandbox& parent) {
23885 u32 n = parent.files_n;
23886 while (n > 0) {
23887 n -= 1;
23888 parent.files_elems[n].~cstring();
23889 parent.files_n = n;
23890 }
23891}
23892
23893// --- command.sandbox.files.RemoveLast
23894// Delete last element of array. Do nothing if array is empty.
23895void command::files_RemoveLast(command::sandbox& parent) {
23896 u64 n = parent.files_n;
23897 if (n > 0) {
23898 n -= 1;
23899 files_qFind(parent, u64(n)).~cstring();
23900 parent.files_n = n;
23901 }
23902}
23903
23904// --- command.sandbox.files.AbsReserve
23905// Make sure N elements fit in array. Process dies if out of memory
23906void command::files_AbsReserve(command::sandbox& parent, int n) {
23907 u32 old_max = parent.files_max;
23908 if (n > i32(old_max)) {
23909 u32 new_max = i32_Max(i32_Max(old_max * 2, n), 4);
23910 void *new_mem = algo_lib::malloc_ReallocMem(parent.files_elems, old_max * sizeof(algo::cstring), new_max * sizeof(algo::cstring));
23911 if (UNLIKELY(!new_mem)) {
23912 FatalErrorExit("command.tary_nomem field:command.sandbox.files comment:'out of memory'");
23913 }
23914 parent.files_elems = (algo::cstring*)new_mem;
23915 parent.files_max = new_max;
23916 }
23917}
23918
23919// --- command.sandbox.files.Setary
23920// Copy contents of RHS to PARENT.
23921void command::files_Setary(command::sandbox& parent, command::sandbox &rhs) {
23922 files_RemoveAll(parent);
23923 int nnew = rhs.files_n;
23924 files_Reserve(parent, nnew); // reserve space
23925 for (int i = 0; i < nnew; i++) { // copy elements over
23926 new (parent.files_elems + i) algo::cstring(files_qFind(rhs, i));
23927 parent.files_n = i + 1;
23928 }
23929}
23930
23931// --- command.sandbox.files.Setary2
23932// Copy specified array into files, discarding previous contents.
23933// If the RHS argument aliases the array (refers to the same memory), throw exception.
23934void command::files_Setary(command::sandbox& parent, const algo::aryptr<algo::cstring> &rhs) {
23935 files_RemoveAll(parent);
23936 files_Addary(parent, rhs);
23937}
23938
23939// --- command.sandbox.files.AllocNVal
23940// Reserve space. Insert N elements at the end of the array, return pointer to array
23941algo::aryptr<algo::cstring> command::files_AllocNVal(command::sandbox& parent, int n_elems, const algo::cstring& val) {
23942 files_Reserve(parent, n_elems);
23943 int old_n = parent.files_n;
23944 int new_n = old_n + n_elems;
23945 algo::cstring *elems = parent.files_elems;
23946 for (int i = old_n; i < new_n; i++) {
23947 new (elems + i) algo::cstring(val);
23948 }
23949 parent.files_n = new_n;
23950 return algo::aryptr<algo::cstring>(elems + old_n, n_elems);
23951}
23952
23953// --- command.sandbox.files.ReadStrptrMaybe
23954// A single element is read from input string and appended to the array.
23955// If the string contains an error, the array is untouched.
23956// Function returns success value.
23957bool command::files_ReadStrptrMaybe(command::sandbox& parent, algo::strptr in_str) {
23958 bool retval = true;
23959 algo::cstring &elem = files_Alloc(parent);
23960 retval = algo::cstring_ReadStrptrMaybe(elem, in_str);
23961 if (!retval) {
23962 files_RemoveLast(parent);
23963 }
23964 return retval;
23965}
23966
23967// --- command.sandbox..ReadFieldMaybe
23968bool command::sandbox_ReadFieldMaybe(command::sandbox& parent, algo::strptr field, algo::strptr strval) {
23969 bool retval = true;
23970 command::FieldId field_id;
23971 (void)value_SetStrptrMaybe(field_id,algo::Pathcomp(field, ".LL"));
23972 switch(field_id) {
23973 case command_FieldId_in: {
23974 retval = algo::cstring_ReadStrptrMaybe(parent.in, strval);
23975 break;
23976 }
23977 case command_FieldId_name: {
23978 retval = name_ReadStrptrMaybe(parent, strval);
23979 break;
23980 }
23981 case command_FieldId_create: {
23982 retval = bool_ReadStrptrMaybe(parent.create, strval);
23983 break;
23984 }
23985 case command_FieldId_list: {
23986 retval = bool_ReadStrptrMaybe(parent.list, strval);
23987 break;
23988 }
23989 case command_FieldId_reset: {
23990 retval = bool_ReadStrptrMaybe(parent.reset, strval);
23991 break;
23992 }
23993 case command_FieldId_clean: {
23994 retval = bool_ReadStrptrMaybe(parent.clean, strval);
23995 break;
23996 }
23997 case command_FieldId_shell: {
23998 retval = bool_ReadStrptrMaybe(parent.shell, strval);
23999 break;
24000 }
24001 case command_FieldId_del: {
24002 retval = bool_ReadStrptrMaybe(parent.del, strval);
24003 break;
24004 }
24005 case command_FieldId_gc: {
24006 retval = bool_ReadStrptrMaybe(parent.gc, strval);
24007 break;
24008 }
24009 case command_FieldId_cmd: {
24010 retval = cmd_ReadStrptrMaybe(parent, strval);
24011 break;
24012 }
24013 case command_FieldId_diff: {
24014 retval = bool_ReadStrptrMaybe(parent.diff, strval);
24015 break;
24016 }
24017 case command_FieldId_files: {
24018 retval = files_ReadStrptrMaybe(parent, strval);
24019 break;
24020 }
24021 case command_FieldId_refs: {
24022 retval = algo::cstring_ReadStrptrMaybe(parent.refs, strval);
24023 break;
24024 }
24025 case command_FieldId_q: {
24026 retval = bool_ReadStrptrMaybe(parent.q, strval);
24027 break;
24028 }
24029 default: break;
24030 }
24031 if (!retval) {
24032 algo_lib::AppendErrtext("attr",field);
24033 }
24034 return retval;
24035}
24036
24037// --- command.sandbox..ReadTupleMaybe
24038// Read fields of command::sandbox from attributes of ascii tuple TUPLE
24039bool command::sandbox_ReadTupleMaybe(command::sandbox &parent, algo::Tuple &tuple) {
24040 bool retval = true;
24041 int anon_idx = 0;
24042 ind_beg(algo::Tuple_attrs_curs,attr,tuple) {
24043 if (ch_N(attr.name) == 0) {
24044 attr.name = sandbox_GetAnon(parent, anon_idx++);
24045 }
24046 retval = sandbox_ReadFieldMaybe(parent, attr.name, attr.value);
24047 if (!retval) {
24048 break;
24049 }
24050 }ind_end;
24051 return retval;
24052}
24053
24054// --- command.sandbox..Init
24055// Set all fields to initial values.
24056void command::sandbox_Init(command::sandbox& parent) {
24057 parent.in = algo::strptr("data");
24058 parent.create = bool(false);
24059 parent.list = bool(false);
24060 parent.reset = bool(false);
24061 parent.clean = bool(false);
24062 parent.shell = bool(false);
24063 parent.del = bool(false);
24064 parent.gc = bool(false);
24065 parent.cmd_elems = 0; // (command.sandbox.cmd)
24066 parent.cmd_n = 0; // (command.sandbox.cmd)
24067 parent.cmd_max = 0; // (command.sandbox.cmd)
24068 parent.diff = bool(false);
24069 parent.files_elems = 0; // (command.sandbox.files)
24070 parent.files_n = 0; // (command.sandbox.files)
24071 parent.files_max = 0; // (command.sandbox.files)
24072 parent.refs = algo::strptr("HEAD");
24073 parent.q = bool(false);
24074}
24075
24076// --- command.sandbox..Uninit
24077void command::sandbox_Uninit(command::sandbox& parent) {
24078 command::sandbox &row = parent; (void)row;
24079
24080 // command.sandbox.files.Uninit (Tary) //Shell regx to diff
24081 // remove all elements from command.sandbox.files
24082 files_RemoveAll(parent);
24083 // free memory for Tary command.sandbox.files
24084 algo_lib::malloc_FreeMem(parent.files_elems, sizeof(algo::cstring)*parent.files_max); // (command.sandbox.files)
24085
24086 // command.sandbox.cmd.Uninit (Tary) //Command to execute in sandbox
24087 // remove all elements from command.sandbox.cmd
24088 cmd_RemoveAll(parent);
24089 // free memory for Tary command.sandbox.cmd
24090 algo_lib::malloc_FreeMem(parent.cmd_elems, sizeof(algo::cstring)*parent.cmd_max); // (command.sandbox.cmd)
24091}
24092
24093// --- command.sandbox..ToCmdline
24094// Convenience function that returns a full command line
24095// Assume command is in a directory called bin
24096tempstr command::sandbox_ToCmdline(command::sandbox& row) {
24097 tempstr ret;
24098 ret << "bin/sandbox ";
24099 sandbox_PrintArgv(row, ret);
24100 // inherit less intense verbose, debug options
24101 for (int i = 1; i < algo_lib::_db.cmdline.verbose; i++) {
24102 ret << " -verbose";
24103 }
24104 for (int i = 1; i < algo_lib::_db.cmdline.debug; i++) {
24105 ret << " -debug";
24106 }
24107 return ret;
24108}
24109
24110// --- command.sandbox..PrintArgv
24111// print string representation of ROW to string STR
24112// cfmt:command.sandbox.Argv printfmt:Tuple
24113void command::sandbox_PrintArgv(command::sandbox& row, algo::cstring& str) {
24114 algo::tempstr temp;
24115 (void)temp;
24116 (void)str;
24117 if (!(row.in == "data")) {
24118 ch_RemoveAll(temp);
24119 cstring_Print(row.in, temp);
24120 str << " -in:";
24121 strptr_PrintBash(temp,str);
24122 }
24123 ch_RemoveAll(temp);
24124 command::name_Print(const_cast<command::sandbox&>(row), temp);
24125 str << " -name:";
24126 strptr_PrintBash(temp,str);
24127 if (!(row.create == false)) {
24128 ch_RemoveAll(temp);
24129 bool_Print(row.create, temp);
24130 str << " -create:";
24131 strptr_PrintBash(temp,str);
24132 }
24133 if (!(row.list == false)) {
24134 ch_RemoveAll(temp);
24135 bool_Print(row.list, temp);
24136 str << " -list:";
24137 strptr_PrintBash(temp,str);
24138 }
24139 if (!(row.reset == false)) {
24140 ch_RemoveAll(temp);
24141 bool_Print(row.reset, temp);
24142 str << " -reset:";
24143 strptr_PrintBash(temp,str);
24144 }
24145 if (!(row.clean == false)) {
24146 ch_RemoveAll(temp);
24147 bool_Print(row.clean, temp);
24148 str << " -clean:";
24149 strptr_PrintBash(temp,str);
24150 }
24151 if (!(row.shell == false)) {
24152 ch_RemoveAll(temp);
24153 bool_Print(row.shell, temp);
24154 str << " -shell:";
24155 strptr_PrintBash(temp,str);
24156 }
24157 if (!(row.del == false)) {
24158 ch_RemoveAll(temp);
24159 bool_Print(row.del, temp);
24160 str << " -del:";
24161 strptr_PrintBash(temp,str);
24162 }
24163 if (!(row.gc == false)) {
24164 ch_RemoveAll(temp);
24165 bool_Print(row.gc, temp);
24166 str << " -gc:";
24167 strptr_PrintBash(temp,str);
24168 }
24169 ind_beg(sandbox_cmd_curs,value,row) {
24170 ch_RemoveAll(temp);
24171 cstring_Print(value, temp);
24172 str << " -cmd:";
24173 strptr_PrintBash(temp,str);
24174 }ind_end;
24175 if (!(row.diff == false)) {
24176 ch_RemoveAll(temp);
24177 bool_Print(row.diff, temp);
24178 str << " -diff:";
24179 strptr_PrintBash(temp,str);
24180 }
24181 ind_beg(sandbox_files_curs,value,row) {
24182 ch_RemoveAll(temp);
24183 cstring_Print(value, temp);
24184 str << " -files:";
24185 strptr_PrintBash(temp,str);
24186 }ind_end;
24187 if (!(row.refs == "HEAD")) {
24188 ch_RemoveAll(temp);
24189 cstring_Print(row.refs, temp);
24190 str << " -refs:";
24191 strptr_PrintBash(temp,str);
24192 }
24193 if (!(row.q == false)) {
24194 ch_RemoveAll(temp);
24195 bool_Print(row.q, temp);
24196 str << " -q:";
24197 strptr_PrintBash(temp,str);
24198 }
24199}
24200
24201// --- command.sandbox..GetAnon
24202algo::strptr command::sandbox_GetAnon(command::sandbox &parent, i32 idx) {
24203 (void)parent;//only to avoid -Wunused-parameter
24204 switch(idx) {
24205 case(0): return strptr("name", 4);
24206 default: return strptr("cmd", 3);
24207 }
24208}
24209
24210// --- command.sandbox..NArgs
24211// Used with command lines
24212// Return # of command-line arguments that must follow this argument
24213// If FIELD is invalid, return -1
24214i32 command::sandbox_NArgs(command::FieldId field, algo::strptr& out_dflt, bool* out_anon) {
24215 i32 retval = 1;
24216 switch (field) {
24217 case command_FieldId_in: { // $comment
24218 *out_anon = false;
24219 } break;
24220 case command_FieldId_name: { // $comment
24221 *out_anon = true;
24222 } break;
24223 case command_FieldId_create: { // $comment
24224 *out_anon = false;
24225 retval=0;
24226 out_dflt="Y";
24227 } break;
24228 case command_FieldId_list: { // bool: no argument required but value may be specified as create:Y
24229 *out_anon = false;
24230 retval=0;
24231 out_dflt="Y";
24232 } break;
24233 case command_FieldId_reset: { // bool: no argument required but value may be specified as list:Y
24234 *out_anon = false;
24235 retval=0;
24236 out_dflt="Y";
24237 } break;
24238 case command_FieldId_clean: { // bool: no argument required but value may be specified as reset:Y
24239 *out_anon = false;
24240 retval=0;
24241 out_dflt="Y";
24242 } break;
24243 case command_FieldId_shell: { // bool: no argument required but value may be specified as clean:Y
24244 *out_anon = false;
24245 retval=0;
24246 out_dflt="Y";
24247 } break;
24248 case command_FieldId_del: { // bool: no argument required but value may be specified as shell:Y
24249 *out_anon = false;
24250 retval=0;
24251 out_dflt="Y";
24252 } break;
24253 case command_FieldId_gc: { // bool: no argument required but value may be specified as del:Y
24254 *out_anon = false;
24255 retval=0;
24256 out_dflt="Y";
24257 } break;
24258 case command_FieldId_cmd: { // bool: no argument required but value may be specified as gc:Y
24259 *out_anon = true;
24260 } break;
24261 case command_FieldId_diff: { // bool: no argument required but value may be specified as gc:Y
24262 *out_anon = false;
24263 retval=0;
24264 out_dflt="Y";
24265 } break;
24266 case command_FieldId_files: { // bool: no argument required but value may be specified as diff:Y
24267 *out_anon = false;
24268 } break;
24269 case command_FieldId_refs: { // bool: no argument required but value may be specified as diff:Y
24270 *out_anon = false;
24271 } break;
24272 case command_FieldId_q: { // bool: no argument required but value may be specified as diff:Y
24273 *out_anon = false;
24274 retval=0;
24275 out_dflt="Y";
24276 } break;
24277 default:
24278 retval=-1; // unrecognized
24279 }
24280 return retval;
24281}
24282
24283// --- command.sandbox_proc.sandbox.Start
24284// Start subprocess
24285// If subprocess already running, do nothing. Otherwise, start it
24286int command::sandbox_Start(command::sandbox_proc& parent) {
24287 int retval = 0;
24288 if (parent.pid == 0) {
24289 verblog(sandbox_ToCmdline(parent)); // maybe print command
24290#ifdef WIN32
24291 algo_lib::ResolveExecFname(parent.path);
24292 tempstr cmdline(sandbox_ToCmdline(parent));
24293 parent.pid = dospawn(Zeroterm(parent.path),Zeroterm(cmdline),parent.timeout,parent.fstdin,parent.fstdout,parent.fstderr);
24294#else
24295 parent.pid = fork();
24296 if (parent.pid == 0) { // child
24297 algo_lib::DieWithParent();
24298 if (parent.timeout > 0) {
24299 alarm(parent.timeout);
24300 }
24301 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstdin , 0);
24302 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstdout, 1);
24303 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstderr, 2);
24304 if (retval==0) retval= sandbox_Execv(parent);
24305 if (retval != 0) { // if start fails, print error
24306 int err=errno;
24307 prerr("command.sandbox_execv"
24308 <<Keyval("errno",err)
24309 <<Keyval("errstr",strerror(err))
24310 <<Keyval("comment","Execv failed"));
24311 }
24312 _exit(127); // if failed to start, exit anyway
24313 } else if (parent.pid == -1) {
24314 retval = errno; // failed to fork
24315 }
24316#endif
24317 }
24318 parent.status = parent.pid > 0 ? 0 : -1; // if didn't start, set error status
24319 return retval;
24320}
24321
24322// --- command.sandbox_proc.sandbox.StartRead
24323// Start subprocess & Read output
24324algo::Fildes command::sandbox_StartRead(command::sandbox_proc& parent, algo_lib::FFildes &read) {
24325 int pipefd[2];
24326 int rc=pipe(pipefd);
24327 (void)rc;
24328 read.fd.value = pipefd[0];
24329 parent.fstdout << ">&" << pipefd[1];
24330 sandbox_Start(parent);
24331 (void)close(pipefd[1]);
24332 return read.fd;
24333}
24334
24335// --- command.sandbox_proc.sandbox.Kill
24336// Kill subprocess and wait
24337void command::sandbox_Kill(command::sandbox_proc& parent) {
24338 if (parent.pid != 0) {
24339 kill(parent.pid,9);
24340 sandbox_Wait(parent);
24341 }
24342}
24343
24344// --- command.sandbox_proc.sandbox.Wait
24345// Wait for subprocess to return
24346void command::sandbox_Wait(command::sandbox_proc& parent) {
24347 if (parent.pid > 0) {
24348 int wait_flags = 0;
24349 int wait_status = 0;
24350 int rc = -1;
24351 do {
24352 // really wait for subprocess to exit
24353 rc = waitpid(parent.pid,&wait_status,wait_flags);
24354 } while (rc==-1 && errno==EINTR);
24355 if (rc == parent.pid) {
24356 parent.status = wait_status;
24357 parent.pid = 0;
24358 }
24359 }
24360}
24361
24362// --- command.sandbox_proc.sandbox.Exec
24363// Start + Wait
24364// Execute subprocess and return exit code
24365int command::sandbox_Exec(command::sandbox_proc& parent) {
24366 sandbox_Start(parent);
24367 sandbox_Wait(parent);
24368 return parent.status;
24369}
24370
24371// --- command.sandbox_proc.sandbox.ExecX
24372// Start + Wait, throw exception on error
24373// Execute subprocess; throw human-readable exception on error
24374void command::sandbox_ExecX(command::sandbox_proc& parent) {
24375 int rc = sandbox_Exec(parent);
24376 vrfy(rc==0, tempstr() << "algo_lib.exec" << Keyval("cmd",sandbox_ToCmdline(parent))
24377 << Keyval("comment",algo::DescribeWaitStatus(parent.status)));
24378}
24379
24380// --- command.sandbox_proc.sandbox.Execv
24381// Call execv()
24382// Call execv with specified parameters
24383int command::sandbox_Execv(command::sandbox_proc& parent) {
24384 int ret = 0;
24385 algo::StringAry args;
24386 sandbox_ToArgv(parent, args);
24387 char **argv = (char**)alloca((ary_N(args)+1)*sizeof(*argv));
24388 ind_beg(algo::StringAry_ary_curs,arg,args) {
24389 argv[ind_curs(arg).index] = Zeroterm(arg);
24390 }ind_end;
24391 argv[ary_N(args)] = NULL;
24392 // if parent.path is relative, search for it in PATH
24393 algo_lib::ResolveExecFname(parent.path);
24394 ret = execv(Zeroterm(parent.path),argv);
24395 return ret;
24396}
24397
24398// --- command.sandbox_proc.sandbox.ToCmdline
24399algo::tempstr command::sandbox_ToCmdline(command::sandbox_proc& parent) {
24400 algo::tempstr retval;
24401 retval << parent.path << " ";
24402 command::sandbox_PrintArgv(parent.cmd,retval);
24403 if (ch_N(parent.fstdin)) {
24404 retval << " " << parent.fstdin;
24405 }
24406 if (ch_N(parent.fstdout)) {
24407 retval << " " << parent.fstdout;
24408 }
24409 if (ch_N(parent.fstderr)) {
24410 retval << " 2" << parent.fstderr;
24411 }
24412 return retval;
24413}
24414
24415// --- command.sandbox_proc.sandbox.ToArgv
24416// Form array from the command line
24417void command::sandbox_ToArgv(command::sandbox_proc& parent, algo::StringAry& args) {
24418 ary_RemoveAll(args);
24419 ary_Alloc(args) << parent.path;
24420
24421 if (parent.cmd.in != "data") {
24422 cstring *arg = &ary_Alloc(args);
24423 *arg << "-in:";
24424 cstring_Print(parent.cmd.in, *arg);
24425 }
24426
24427 if (true) {
24428 cstring *arg = &ary_Alloc(args);
24429 *arg << "-name:";
24430 command::name_Print(parent.cmd, *arg);
24431 }
24432
24433 if (parent.cmd.create != false) {
24434 cstring *arg = &ary_Alloc(args);
24435 *arg << "-create:";
24436 bool_Print(parent.cmd.create, *arg);
24437 }
24438
24439 if (parent.cmd.list != false) {
24440 cstring *arg = &ary_Alloc(args);
24441 *arg << "-list:";
24442 bool_Print(parent.cmd.list, *arg);
24443 }
24444
24445 if (parent.cmd.reset != false) {
24446 cstring *arg = &ary_Alloc(args);
24447 *arg << "-reset:";
24448 bool_Print(parent.cmd.reset, *arg);
24449 }
24450
24451 if (parent.cmd.clean != false) {
24452 cstring *arg = &ary_Alloc(args);
24453 *arg << "-clean:";
24454 bool_Print(parent.cmd.clean, *arg);
24455 }
24456
24457 if (parent.cmd.shell != false) {
24458 cstring *arg = &ary_Alloc(args);
24459 *arg << "-shell:";
24460 bool_Print(parent.cmd.shell, *arg);
24461 }
24462
24463 if (parent.cmd.del != false) {
24464 cstring *arg = &ary_Alloc(args);
24465 *arg << "-del:";
24466 bool_Print(parent.cmd.del, *arg);
24467 }
24468
24469 if (parent.cmd.gc != false) {
24470 cstring *arg = &ary_Alloc(args);
24471 *arg << "-gc:";
24472 bool_Print(parent.cmd.gc, *arg);
24473 }
24474 ind_beg(command::sandbox_cmd_curs,value,parent.cmd) {
24475 cstring *arg = &ary_Alloc(args);
24476 *arg << "-cmd:";
24477 cstring_Print(value, *arg);
24478 }ind_end;
24479
24480 if (parent.cmd.diff != false) {
24481 cstring *arg = &ary_Alloc(args);
24482 *arg << "-diff:";
24483 bool_Print(parent.cmd.diff, *arg);
24484 }
24485 ind_beg(command::sandbox_files_curs,value,parent.cmd) {
24486 cstring *arg = &ary_Alloc(args);
24487 *arg << "-files:";
24488 cstring_Print(value, *arg);
24489 }ind_end;
24490
24491 if (parent.cmd.refs != "HEAD") {
24492 cstring *arg = &ary_Alloc(args);
24493 *arg << "-refs:";
24494 cstring_Print(parent.cmd.refs, *arg);
24495 }
24496
24497 if (parent.cmd.q != false) {
24498 cstring *arg = &ary_Alloc(args);
24499 *arg << "-q:";
24500 bool_Print(parent.cmd.q, *arg);
24501 }
24502 for (int i=1; i < algo_lib::_db.cmdline.verbose; ++i) {
24503 ary_Alloc(args) << "-verbose";
24504 }
24505}
24506
24507// --- command.sandbox_proc..Uninit
24508void command::sandbox_proc_Uninit(command::sandbox_proc& parent) {
24509 command::sandbox_proc &row = parent; (void)row;
24510
24511 // command.sandbox_proc.sandbox.Uninit (Exec) //
24512 sandbox_Kill(parent); // kill child, ensure forward progress
24513}
24514
24515// --- command.spnx..ReadFieldMaybe
24516bool command::spnx_ReadFieldMaybe(command::spnx& parent, algo::strptr field, algo::strptr strval) {
24517 bool retval = true;
24518 command::FieldId field_id;
24519 (void)value_SetStrptrMaybe(field_id,field);
24520 switch(field_id) {
24521 case command_FieldId_in: {
24522 retval = algo::cstring_ReadStrptrMaybe(parent.in, strval);
24523 break;
24524 }
24525 case command_FieldId_site: {
24526 retval = algo::Smallstr50_ReadStrptrMaybe(parent.site, strval);
24527 break;
24528 }
24529 case command_FieldId_build: {
24530 retval = bool_ReadStrptrMaybe(parent.build, strval);
24531 break;
24532 }
24533 case command_FieldId_builder: {
24534 retval = algo::Smallstr50_ReadStrptrMaybe(parent.builder, strval);
24535 break;
24536 }
24537 case command_FieldId_build_fail_on_warning: {
24538 retval = bool_ReadStrptrMaybe(parent.build_fail_on_warning, strval);
24539 break;
24540 }
24541 case command_FieldId_build_quiet: {
24542 retval = bool_ReadStrptrMaybe(parent.build_quiet, strval);
24543 break;
24544 }
24545 case command_FieldId_jobs: {
24546 retval = u32_ReadStrptrMaybe(parent.jobs, strval);
24547 break;
24548 }
24549 case command_FieldId_preserve_footer: {
24550 retval = bool_ReadStrptrMaybe(parent.preserve_footer, strval);
24551 break;
24552 }
24553 case command_FieldId_clean: {
24554 retval = bool_ReadStrptrMaybe(parent.clean, strval);
24555 break;
24556 }
24557 case command_FieldId_serve: {
24558 retval = bool_ReadStrptrMaybe(parent.serve, strval);
24559 break;
24560 }
24561 case command_FieldId_serve_dctrhost: {
24562 retval = algo::Smallstr50_ReadStrptrMaybe(parent.serve_dctrhost, strval);
24563 break;
24564 }
24565 case command_FieldId_serve_pages: {
24566 retval = bool_ReadStrptrMaybe(parent.serve_pages, strval);
24567 break;
24568 }
24569 case command_FieldId_serve_verify: {
24570 retval = bool_ReadStrptrMaybe(parent.serve_verify, strval);
24571 break;
24572 }
24573 case command_FieldId_workdir: {
24574 retval = algo::cstring_ReadStrptrMaybe(parent.workdir, strval);
24575 break;
24576 }
24577 case command_FieldId_dry_run: {
24578 retval = bool_ReadStrptrMaybe(parent.dry_run, strval);
24579 break;
24580 }
24581 case command_FieldId_opts_numbered: {
24582 retval = bool_ReadStrptrMaybe(parent.opts_numbered, strval);
24583 break;
24584 }
24585 default: break;
24586 }
24587 if (!retval) {
24588 algo_lib::AppendErrtext("attr",field);
24589 }
24590 return retval;
24591}
24592
24593// --- command.spnx..ReadTupleMaybe
24594// Read fields of command::spnx from attributes of ascii tuple TUPLE
24595bool command::spnx_ReadTupleMaybe(command::spnx &parent, algo::Tuple &tuple) {
24596 bool retval = true;
24597 ind_beg(algo::Tuple_attrs_curs,attr,tuple) {
24598 retval = spnx_ReadFieldMaybe(parent, attr.name, attr.value);
24599 if (!retval) {
24600 break;
24601 }
24602 }ind_end;
24603 return retval;
24604}
24605
24606// --- command.spnx..Init
24607// Set all fields to initial values.
24608void command::spnx_Init(command::spnx& parent) {
24609 parent.in = algo::strptr("data");
24610 parent.site = algo::strptr("OpenacrDoc");
24611 parent.build = bool(false);
24612 parent.builder = algo::strptr("html");
24613 parent.build_fail_on_warning = bool(false);
24614 parent.build_quiet = bool(false);
24615 parent.jobs = u32(0);
24616 parent.preserve_footer = bool(false);
24617 parent.clean = bool(false);
24618 parent.serve = bool(false);
24619 parent.serve_dctrhost = algo::strptr("");
24620 parent.serve_pages = bool(false);
24621 parent.serve_verify = bool(false);
24622 parent.workdir = algo::strptr("temp/");
24623 parent.dry_run = bool(false);
24624 parent.opts_numbered = bool(false);
24625}
24626
24627// --- command.spnx..ToCmdline
24628// Convenience function that returns a full command line
24629// Assume command is in a directory called bin
24630tempstr command::spnx_ToCmdline(command::spnx& row) {
24631 tempstr ret;
24632 ret << "bin/spnx ";
24633 spnx_PrintArgv(row, ret);
24634 // inherit less intense verbose, debug options
24635 for (int i = 1; i < algo_lib::_db.cmdline.verbose; i++) {
24636 ret << " -verbose";
24637 }
24638 for (int i = 1; i < algo_lib::_db.cmdline.debug; i++) {
24639 ret << " -debug";
24640 }
24641 return ret;
24642}
24643
24644// --- command.spnx..PrintArgv
24645// print string representation of ROW to string STR
24646// cfmt:command.spnx.Argv printfmt:Tuple
24647void command::spnx_PrintArgv(command::spnx& row, algo::cstring& str) {
24648 algo::tempstr temp;
24649 (void)temp;
24650 (void)str;
24651 if (!(row.in == "data")) {
24652 ch_RemoveAll(temp);
24653 cstring_Print(row.in, temp);
24654 str << " -in:";
24655 strptr_PrintBash(temp,str);
24656 }
24657 if (!(row.site == "OpenacrDoc")) {
24658 ch_RemoveAll(temp);
24659 Smallstr50_Print(row.site, temp);
24660 str << " -site:";
24661 strptr_PrintBash(temp,str);
24662 }
24663 if (!(row.build == false)) {
24664 ch_RemoveAll(temp);
24665 bool_Print(row.build, temp);
24666 str << " -build:";
24667 strptr_PrintBash(temp,str);
24668 }
24669 if (!(row.builder == "html")) {
24670 ch_RemoveAll(temp);
24671 Smallstr50_Print(row.builder, temp);
24672 str << " -builder:";
24673 strptr_PrintBash(temp,str);
24674 }
24675 if (!(row.build_fail_on_warning == false)) {
24676 ch_RemoveAll(temp);
24677 bool_Print(row.build_fail_on_warning, temp);
24678 str << " -build_fail_on_warning:";
24679 strptr_PrintBash(temp,str);
24680 }
24681 if (!(row.build_quiet == false)) {
24682 ch_RemoveAll(temp);
24683 bool_Print(row.build_quiet, temp);
24684 str << " -build_quiet:";
24685 strptr_PrintBash(temp,str);
24686 }
24687 if (!(row.jobs == 0)) {
24688 ch_RemoveAll(temp);
24689 u32_Print(row.jobs, temp);
24690 str << " -jobs:";
24691 strptr_PrintBash(temp,str);
24692 }
24693 if (!(row.preserve_footer == false)) {
24694 ch_RemoveAll(temp);
24695 bool_Print(row.preserve_footer, temp);
24696 str << " -preserve_footer:";
24697 strptr_PrintBash(temp,str);
24698 }
24699 if (!(row.clean == false)) {
24700 ch_RemoveAll(temp);
24701 bool_Print(row.clean, temp);
24702 str << " -clean:";
24703 strptr_PrintBash(temp,str);
24704 }
24705 if (!(row.serve == false)) {
24706 ch_RemoveAll(temp);
24707 bool_Print(row.serve, temp);
24708 str << " -serve:";
24709 strptr_PrintBash(temp,str);
24710 }
24711 if (!(row.serve_dctrhost == "")) {
24712 ch_RemoveAll(temp);
24713 Smallstr50_Print(row.serve_dctrhost, temp);
24714 str << " -serve_dctrhost:";
24715 strptr_PrintBash(temp,str);
24716 }
24717 if (!(row.serve_pages == false)) {
24718 ch_RemoveAll(temp);
24719 bool_Print(row.serve_pages, temp);
24720 str << " -serve_pages:";
24721 strptr_PrintBash(temp,str);
24722 }
24723 if (!(row.serve_verify == false)) {
24724 ch_RemoveAll(temp);
24725 bool_Print(row.serve_verify, temp);
24726 str << " -serve_verify:";
24727 strptr_PrintBash(temp,str);
24728 }
24729 if (!(row.workdir == "temp/")) {
24730 ch_RemoveAll(temp);
24731 cstring_Print(row.workdir, temp);
24732 str << " -workdir:";
24733 strptr_PrintBash(temp,str);
24734 }
24735 if (!(row.dry_run == false)) {
24736 ch_RemoveAll(temp);
24737 bool_Print(row.dry_run, temp);
24738 str << " -dry_run:";
24739 strptr_PrintBash(temp,str);
24740 }
24741 if (!(row.opts_numbered == false)) {
24742 ch_RemoveAll(temp);
24743 bool_Print(row.opts_numbered, temp);
24744 str << " -opts_numbered:";
24745 strptr_PrintBash(temp,str);
24746 }
24747}
24748
24749// --- command.spnx..NArgs
24750// Used with command lines
24751// Return # of command-line arguments that must follow this argument
24752// If FIELD is invalid, return -1
24753i32 command::spnx_NArgs(command::FieldId field, algo::strptr& out_dflt, bool* out_anon) {
24754 i32 retval = 1;
24755 switch (field) {
24756 case command_FieldId_in: { // $comment
24757 *out_anon = false;
24758 } break;
24759 case command_FieldId_site: { // $comment
24760 *out_anon = false;
24761 } break;
24762 case command_FieldId_build: { // $comment
24763 *out_anon = false;
24764 retval=0;
24765 out_dflt="Y";
24766 } break;
24767 case command_FieldId_builder: { // bool: no argument required but value may be specified as build:Y
24768 *out_anon = false;
24769 } break;
24770 case command_FieldId_build_fail_on_warning: { // bool: no argument required but value may be specified as build:Y
24771 *out_anon = false;
24772 retval=0;
24773 out_dflt="Y";
24774 } break;
24775 case command_FieldId_build_quiet: { // bool: no argument required but value may be specified as build_fail_on_warning:Y
24776 *out_anon = false;
24777 retval=0;
24778 out_dflt="Y";
24779 } break;
24780 case command_FieldId_jobs: { // bool: no argument required but value may be specified as build_quiet:Y
24781 *out_anon = false;
24782 } break;
24783 case command_FieldId_preserve_footer: { // bool: no argument required but value may be specified as build_quiet:Y
24784 *out_anon = false;
24785 retval=0;
24786 out_dflt="Y";
24787 } break;
24788 case command_FieldId_clean: { // bool: no argument required but value may be specified as preserve_footer:Y
24789 *out_anon = false;
24790 retval=0;
24791 out_dflt="Y";
24792 } break;
24793 case command_FieldId_serve: { // bool: no argument required but value may be specified as clean:Y
24794 *out_anon = false;
24795 retval=0;
24796 out_dflt="Y";
24797 } break;
24798 case command_FieldId_serve_dctrhost: { // bool: no argument required but value may be specified as serve:Y
24799 *out_anon = false;
24800 } break;
24801 case command_FieldId_serve_pages: { // bool: no argument required but value may be specified as serve:Y
24802 *out_anon = false;
24803 retval=0;
24804 out_dflt="Y";
24805 } break;
24806 case command_FieldId_serve_verify: { // bool: no argument required but value may be specified as serve_pages:Y
24807 *out_anon = false;
24808 retval=0;
24809 out_dflt="Y";
24810 } break;
24811 case command_FieldId_workdir: { // bool: no argument required but value may be specified as serve_verify:Y
24812 *out_anon = false;
24813 } break;
24814 case command_FieldId_dry_run: { // bool: no argument required but value may be specified as serve_verify:Y
24815 *out_anon = false;
24816 retval=0;
24817 out_dflt="Y";
24818 } break;
24819 case command_FieldId_opts_numbered: { // bool: no argument required but value may be specified as dry_run:Y
24820 *out_anon = false;
24821 retval=0;
24822 out_dflt="Y";
24823 } break;
24824 default:
24825 retval=-1; // unrecognized
24826 }
24827 return retval;
24828}
24829
24830// --- command.spnx_proc.spnx.Start
24831// Start subprocess
24832// If subprocess already running, do nothing. Otherwise, start it
24833int command::spnx_Start(command::spnx_proc& parent) {
24834 int retval = 0;
24835 if (parent.pid == 0) {
24836 verblog(spnx_ToCmdline(parent)); // maybe print command
24837#ifdef WIN32
24838 algo_lib::ResolveExecFname(parent.path);
24839 tempstr cmdline(spnx_ToCmdline(parent));
24840 parent.pid = dospawn(Zeroterm(parent.path),Zeroterm(cmdline),parent.timeout,parent.fstdin,parent.fstdout,parent.fstderr);
24841#else
24842 parent.pid = fork();
24843 if (parent.pid == 0) { // child
24844 algo_lib::DieWithParent();
24845 if (parent.timeout > 0) {
24846 alarm(parent.timeout);
24847 }
24848 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstdin , 0);
24849 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstdout, 1);
24850 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstderr, 2);
24851 if (retval==0) retval= spnx_Execv(parent);
24852 if (retval != 0) { // if start fails, print error
24853 int err=errno;
24854 prerr("command.spnx_execv"
24855 <<Keyval("errno",err)
24856 <<Keyval("errstr",strerror(err))
24857 <<Keyval("comment","Execv failed"));
24858 }
24859 _exit(127); // if failed to start, exit anyway
24860 } else if (parent.pid == -1) {
24861 retval = errno; // failed to fork
24862 }
24863#endif
24864 }
24865 parent.status = parent.pid > 0 ? 0 : -1; // if didn't start, set error status
24866 return retval;
24867}
24868
24869// --- command.spnx_proc.spnx.StartRead
24870// Start subprocess & Read output
24871algo::Fildes command::spnx_StartRead(command::spnx_proc& parent, algo_lib::FFildes &read) {
24872 int pipefd[2];
24873 int rc=pipe(pipefd);
24874 (void)rc;
24875 read.fd.value = pipefd[0];
24876 parent.fstdout << ">&" << pipefd[1];
24877 spnx_Start(parent);
24878 (void)close(pipefd[1]);
24879 return read.fd;
24880}
24881
24882// --- command.spnx_proc.spnx.Kill
24883// Kill subprocess and wait
24884void command::spnx_Kill(command::spnx_proc& parent) {
24885 if (parent.pid != 0) {
24886 kill(parent.pid,9);
24887 spnx_Wait(parent);
24888 }
24889}
24890
24891// --- command.spnx_proc.spnx.Wait
24892// Wait for subprocess to return
24893void command::spnx_Wait(command::spnx_proc& parent) {
24894 if (parent.pid > 0) {
24895 int wait_flags = 0;
24896 int wait_status = 0;
24897 int rc = -1;
24898 do {
24899 // really wait for subprocess to exit
24900 rc = waitpid(parent.pid,&wait_status,wait_flags);
24901 } while (rc==-1 && errno==EINTR);
24902 if (rc == parent.pid) {
24903 parent.status = wait_status;
24904 parent.pid = 0;
24905 }
24906 }
24907}
24908
24909// --- command.spnx_proc.spnx.Exec
24910// Start + Wait
24911// Execute subprocess and return exit code
24912int command::spnx_Exec(command::spnx_proc& parent) {
24913 spnx_Start(parent);
24914 spnx_Wait(parent);
24915 return parent.status;
24916}
24917
24918// --- command.spnx_proc.spnx.ExecX
24919// Start + Wait, throw exception on error
24920// Execute subprocess; throw human-readable exception on error
24921void command::spnx_ExecX(command::spnx_proc& parent) {
24922 int rc = spnx_Exec(parent);
24923 vrfy(rc==0, tempstr() << "algo_lib.exec" << Keyval("cmd",spnx_ToCmdline(parent))
24924 << Keyval("comment",algo::DescribeWaitStatus(parent.status)));
24925}
24926
24927// --- command.spnx_proc.spnx.Execv
24928// Call execv()
24929// Call execv with specified parameters
24930int command::spnx_Execv(command::spnx_proc& parent) {
24931 int ret = 0;
24932 algo::StringAry args;
24933 spnx_ToArgv(parent, args);
24934 char **argv = (char**)alloca((ary_N(args)+1)*sizeof(*argv));
24935 ind_beg(algo::StringAry_ary_curs,arg,args) {
24936 argv[ind_curs(arg).index] = Zeroterm(arg);
24937 }ind_end;
24938 argv[ary_N(args)] = NULL;
24939 // if parent.path is relative, search for it in PATH
24940 algo_lib::ResolveExecFname(parent.path);
24941 ret = execv(Zeroterm(parent.path),argv);
24942 return ret;
24943}
24944
24945// --- command.spnx_proc.spnx.ToCmdline
24946algo::tempstr command::spnx_ToCmdline(command::spnx_proc& parent) {
24947 algo::tempstr retval;
24948 retval << parent.path << " ";
24949 command::spnx_PrintArgv(parent.cmd,retval);
24950 if (ch_N(parent.fstdin)) {
24951 retval << " " << parent.fstdin;
24952 }
24953 if (ch_N(parent.fstdout)) {
24954 retval << " " << parent.fstdout;
24955 }
24956 if (ch_N(parent.fstderr)) {
24957 retval << " 2" << parent.fstderr;
24958 }
24959 return retval;
24960}
24961
24962// --- command.spnx_proc.spnx.ToArgv
24963// Form array from the command line
24964void command::spnx_ToArgv(command::spnx_proc& parent, algo::StringAry& args) {
24965 ary_RemoveAll(args);
24966 ary_Alloc(args) << parent.path;
24967
24968 if (parent.cmd.in != "data") {
24969 cstring *arg = &ary_Alloc(args);
24970 *arg << "-in:";
24971 cstring_Print(parent.cmd.in, *arg);
24972 }
24973
24974 if (parent.cmd.site != "OpenacrDoc") {
24975 cstring *arg = &ary_Alloc(args);
24976 *arg << "-site:";
24977 Smallstr50_Print(parent.cmd.site, *arg);
24978 }
24979
24980 if (parent.cmd.build != false) {
24981 cstring *arg = &ary_Alloc(args);
24982 *arg << "-build:";
24983 bool_Print(parent.cmd.build, *arg);
24984 }
24985
24986 if (parent.cmd.builder != "html") {
24987 cstring *arg = &ary_Alloc(args);
24988 *arg << "-builder:";
24989 Smallstr50_Print(parent.cmd.builder, *arg);
24990 }
24991
24992 if (parent.cmd.build_fail_on_warning != false) {
24993 cstring *arg = &ary_Alloc(args);
24994 *arg << "-build_fail_on_warning:";
24995 bool_Print(parent.cmd.build_fail_on_warning, *arg);
24996 }
24997
24998 if (parent.cmd.build_quiet != false) {
24999 cstring *arg = &ary_Alloc(args);
25000 *arg << "-build_quiet:";
25001 bool_Print(parent.cmd.build_quiet, *arg);
25002 }
25003
25004 if (parent.cmd.jobs != 0) {
25005 cstring *arg = &ary_Alloc(args);
25006 *arg << "-jobs:";
25007 u32_Print(parent.cmd.jobs, *arg);
25008 }
25009
25010 if (parent.cmd.preserve_footer != false) {
25011 cstring *arg = &ary_Alloc(args);
25012 *arg << "-preserve_footer:";
25013 bool_Print(parent.cmd.preserve_footer, *arg);
25014 }
25015
25016 if (parent.cmd.clean != false) {
25017 cstring *arg = &ary_Alloc(args);
25018 *arg << "-clean:";
25019 bool_Print(parent.cmd.clean, *arg);
25020 }
25021
25022 if (parent.cmd.serve != false) {
25023 cstring *arg = &ary_Alloc(args);
25024 *arg << "-serve:";
25025 bool_Print(parent.cmd.serve, *arg);
25026 }
25027
25028 if (parent.cmd.serve_dctrhost != "") {
25029 cstring *arg = &ary_Alloc(args);
25030 *arg << "-serve_dctrhost:";
25031 Smallstr50_Print(parent.cmd.serve_dctrhost, *arg);
25032 }
25033
25034 if (parent.cmd.serve_pages != false) {
25035 cstring *arg = &ary_Alloc(args);
25036 *arg << "-serve_pages:";
25037 bool_Print(parent.cmd.serve_pages, *arg);
25038 }
25039
25040 if (parent.cmd.serve_verify != false) {
25041 cstring *arg = &ary_Alloc(args);
25042 *arg << "-serve_verify:";
25043 bool_Print(parent.cmd.serve_verify, *arg);
25044 }
25045
25046 if (parent.cmd.workdir != "temp/") {
25047 cstring *arg = &ary_Alloc(args);
25048 *arg << "-workdir:";
25049 cstring_Print(parent.cmd.workdir, *arg);
25050 }
25051
25052 if (parent.cmd.dry_run != false) {
25053 cstring *arg = &ary_Alloc(args);
25054 *arg << "-dry_run:";
25055 bool_Print(parent.cmd.dry_run, *arg);
25056 }
25057
25058 if (parent.cmd.opts_numbered != false) {
25059 cstring *arg = &ary_Alloc(args);
25060 *arg << "-opts_numbered:";
25061 bool_Print(parent.cmd.opts_numbered, *arg);
25062 }
25063 for (int i=1; i < algo_lib::_db.cmdline.verbose; ++i) {
25064 ary_Alloc(args) << "-verbose";
25065 }
25066}
25067
25068// --- command.spnx_proc..Uninit
25069void command::spnx_proc_Uninit(command::spnx_proc& parent) {
25070 command::spnx_proc &row = parent; (void)row;
25071
25072 // command.spnx_proc.spnx.Uninit (Exec) //
25073 spnx_Kill(parent); // kill child, ensure forward progress
25074}
25075
25076// --- command.src_func.target.Print
25077// Print back to string
25078void command::target_Print(command::src_func& parent, algo::cstring &out) {
25079 Regx_Print(parent.target, out);
25080}
25081
25082// --- command.src_func.target.ReadStrptrMaybe
25083// Read Regx from string
25084// Convert string to field. Return success value
25085bool command::target_ReadStrptrMaybe(command::src_func& parent, algo::strptr in) {
25086 bool retval = true;
25087 Regx_ReadSql(parent.target, in, true);
25088 return retval;
25089}
25090
25091// --- command.src_func.name.Print
25092// Print back to string
25093void command::name_Print(command::src_func& parent, algo::cstring &out) {
25094 Regx_Print(parent.name, out);
25095}
25096
25097// --- command.src_func.name.ReadStrptrMaybe
25098// Read Regx from string
25099// Convert string to field. Return success value
25100bool command::name_ReadStrptrMaybe(command::src_func& parent, algo::strptr in) {
25101 bool retval = true;
25102 Regx_ReadSql(parent.name, in, true);
25103 return retval;
25104}
25105
25106// --- command.src_func.body.Print
25107// Print back to string
25108void command::body_Print(command::src_func& parent, algo::cstring &out) {
25109 Regx_Print(parent.body, out);
25110}
25111
25112// --- command.src_func.body.ReadStrptrMaybe
25113// Read Regx from string
25114// Convert string to field. Return success value
25115bool command::body_ReadStrptrMaybe(command::src_func& parent, algo::strptr in) {
25116 bool retval = true;
25117 Regx_ReadSql(parent.body, in, true);
25118 return retval;
25119}
25120
25121// --- command.src_func.targsrc.Print
25122// Print back to string
25123void command::targsrc_Print(command::src_func& parent, algo::cstring &out) {
25124 Regx_Print(parent.targsrc, out);
25125}
25126
25127// --- command.src_func.targsrc.ReadStrptrMaybe
25128// Read Regx from string
25129// Convert string to field. Return success value
25130bool command::targsrc_ReadStrptrMaybe(command::src_func& parent, algo::strptr in) {
25131 bool retval = true;
25132 Regx_ReadSql(parent.targsrc, in, true);
25133 return retval;
25134}
25135
25136// --- command.src_func.func.Print
25137// Print back to string
25138void command::func_Print(command::src_func& parent, algo::cstring &out) {
25139 Regx_Print(parent.func, out);
25140}
25141
25142// --- command.src_func.func.ReadStrptrMaybe
25143// Read Regx from string
25144// Convert string to field. Return success value
25145bool command::func_ReadStrptrMaybe(command::src_func& parent, algo::strptr in) {
25146 bool retval = true;
25147 Regx_ReadSql(parent.func, in, true);
25148 return retval;
25149}
25150
25151// --- command.src_func.comment.Print
25152// Print back to string
25153void command::comment_Print(command::src_func& parent, algo::cstring &out) {
25154 Regx_Print(parent.comment, out);
25155}
25156
25157// --- command.src_func.comment.ReadStrptrMaybe
25158// Read Regx from string
25159// Convert string to field. Return success value
25160bool command::comment_ReadStrptrMaybe(command::src_func& parent, algo::strptr in) {
25161 bool retval = true;
25162 Regx_ReadSql(parent.comment, in, true);
25163 return retval;
25164}
25165
25166// --- command.src_func..ReadFieldMaybe
25167bool command::src_func_ReadFieldMaybe(command::src_func& parent, algo::strptr field, algo::strptr strval) {
25168 bool retval = true;
25169 command::FieldId field_id;
25170 (void)value_SetStrptrMaybe(field_id,field);
25171 switch(field_id) {
25172 case command_FieldId_in: {
25173 retval = algo::cstring_ReadStrptrMaybe(parent.in, strval);
25174 break;
25175 }
25176 case command_FieldId_target: {
25177 retval = target_ReadStrptrMaybe(parent, strval);
25178 break;
25179 }
25180 case command_FieldId_name: {
25181 retval = name_ReadStrptrMaybe(parent, strval);
25182 break;
25183 }
25184 case command_FieldId_body: {
25185 retval = body_ReadStrptrMaybe(parent, strval);
25186 break;
25187 }
25188 case command_FieldId_targsrc: {
25189 retval = targsrc_ReadStrptrMaybe(parent, strval);
25190 break;
25191 }
25192 case command_FieldId_func: {
25193 retval = func_ReadStrptrMaybe(parent, strval);
25194 break;
25195 }
25196 case command_FieldId_comment: {
25197 retval = comment_ReadStrptrMaybe(parent, strval);
25198 break;
25199 }
25200 case command_FieldId_nextfile: {
25201 retval = algo::Smallstr200_ReadStrptrMaybe(parent.nextfile, strval);
25202 break;
25203 }
25204 case command_FieldId_other: {
25205 retval = bool_ReadStrptrMaybe(parent.other, strval);
25206 break;
25207 }
25208 case command_FieldId_updateproto: {
25209 retval = bool_ReadStrptrMaybe(parent.updateproto, strval);
25210 break;
25211 }
25212 case command_FieldId_listfunc: {
25213 retval = bool_ReadStrptrMaybe(parent.listfunc, strval);
25214 break;
25215 }
25216 case command_FieldId_iffy: {
25217 retval = bool_ReadStrptrMaybe(parent.iffy, strval);
25218 break;
25219 }
25220 case command_FieldId_proto: {
25221 retval = bool_ReadStrptrMaybe(parent.proto, strval);
25222 break;
25223 }
25224 case command_FieldId_gen: {
25225 retval = bool_ReadStrptrMaybe(parent.gen, strval);
25226 break;
25227 }
25228 case command_FieldId_showloc: {
25229 retval = bool_ReadStrptrMaybe(parent.showloc, strval);
25230 break;
25231 }
25232 case command_FieldId_showstatic: {
25233 retval = bool_ReadStrptrMaybe(parent.showstatic, strval);
25234 break;
25235 }
25236 case command_FieldId_showsortkey: {
25237 retval = bool_ReadStrptrMaybe(parent.showsortkey, strval);
25238 break;
25239 }
25240 case command_FieldId_sortname: {
25241 retval = bool_ReadStrptrMaybe(parent.sortname, strval);
25242 break;
25243 }
25244 case command_FieldId_e: {
25245 retval = bool_ReadStrptrMaybe(parent.e, strval);
25246 break;
25247 }
25248 case command_FieldId_baddecl: {
25249 retval = bool_ReadStrptrMaybe(parent.baddecl, strval);
25250 break;
25251 }
25252 case command_FieldId_report: {
25253 retval = bool_ReadStrptrMaybe(parent.report, strval);
25254 break;
25255 }
25256 default: break;
25257 }
25258 if (!retval) {
25259 algo_lib::AppendErrtext("attr",field);
25260 }
25261 return retval;
25262}
25263
25264// --- command.src_func..ReadTupleMaybe
25265// Read fields of command::src_func from attributes of ascii tuple TUPLE
25266bool command::src_func_ReadTupleMaybe(command::src_func &parent, algo::Tuple &tuple) {
25267 bool retval = true;
25268 int anon_idx = 0;
25269 ind_beg(algo::Tuple_attrs_curs,attr,tuple) {
25270 if (ch_N(attr.name) == 0) {
25271 attr.name = src_func_GetAnon(parent, anon_idx++);
25272 }
25273 retval = src_func_ReadFieldMaybe(parent, attr.name, attr.value);
25274 if (!retval) {
25275 break;
25276 }
25277 }ind_end;
25278 return retval;
25279}
25280
25281// --- command.src_func..Init
25282// Set all fields to initial values.
25283void command::src_func_Init(command::src_func& parent) {
25284 parent.in = algo::strptr("data");
25285 Regx_ReadSql(parent.target, "%", true);
25286 Regx_ReadSql(parent.name, "%", true);
25287 Regx_ReadSql(parent.body, "%", true);
25288 Regx_ReadSql(parent.targsrc, "", true);
25289 Regx_ReadSql(parent.func, "%", true);
25290 Regx_ReadSql(parent.comment, "%", true);
25291 parent.nextfile = algo::strptr("");
25292 parent.other = bool(false);
25293 parent.updateproto = bool(false);
25294 parent.listfunc = bool(false);
25295 parent.iffy = bool(false);
25296 parent.proto = bool(false);
25297 parent.gen = bool(false);
25298 parent.showloc = bool(true);
25299 parent.showstatic = bool(true);
25300 parent.showsortkey = bool(false);
25301 parent.sortname = bool(false);
25302 parent.e = bool(false);
25303 parent.baddecl = bool(false);
25304 parent.report = bool(false);
25305}
25306
25307// --- command.src_func..ToCmdline
25308// Convenience function that returns a full command line
25309// Assume command is in a directory called bin
25310tempstr command::src_func_ToCmdline(command::src_func& row) {
25311 tempstr ret;
25312 ret << "bin/src_func ";
25313 src_func_PrintArgv(row, ret);
25314 // inherit less intense verbose, debug options
25315 for (int i = 1; i < algo_lib::_db.cmdline.verbose; i++) {
25316 ret << " -verbose";
25317 }
25318 for (int i = 1; i < algo_lib::_db.cmdline.debug; i++) {
25319 ret << " -debug";
25320 }
25321 return ret;
25322}
25323
25324// --- command.src_func..PrintArgv
25325// print string representation of ROW to string STR
25326// cfmt:command.src_func.Argv printfmt:Tuple
25327void command::src_func_PrintArgv(command::src_func& row, algo::cstring& str) {
25328 algo::tempstr temp;
25329 (void)temp;
25330 (void)str;
25331 if (!(row.in == "data")) {
25332 ch_RemoveAll(temp);
25333 cstring_Print(row.in, temp);
25334 str << " -in:";
25335 strptr_PrintBash(temp,str);
25336 }
25337 ch_RemoveAll(temp);
25338 command::target_Print(const_cast<command::src_func&>(row), temp);
25339 str << " -target:";
25340 strptr_PrintBash(temp,str);
25341 ch_RemoveAll(temp);
25342 command::name_Print(const_cast<command::src_func&>(row), temp);
25343 str << " -name:";
25344 strptr_PrintBash(temp,str);
25345 ch_RemoveAll(temp);
25346 command::body_Print(const_cast<command::src_func&>(row), temp);
25347 str << " -body:";
25348 strptr_PrintBash(temp,str);
25349 if (!(row.targsrc.expr == "")) {
25350 ch_RemoveAll(temp);
25351 command::targsrc_Print(const_cast<command::src_func&>(row), temp);
25352 str << " -targsrc:";
25353 strptr_PrintBash(temp,str);
25354 }
25355 if (!(row.func.expr == "%")) {
25356 ch_RemoveAll(temp);
25357 command::func_Print(const_cast<command::src_func&>(row), temp);
25358 str << " -func:";
25359 strptr_PrintBash(temp,str);
25360 }
25361 if (!(row.comment.expr == "%")) {
25362 ch_RemoveAll(temp);
25363 command::comment_Print(const_cast<command::src_func&>(row), temp);
25364 str << " -comment:";
25365 strptr_PrintBash(temp,str);
25366 }
25367 if (!(row.nextfile == "")) {
25368 ch_RemoveAll(temp);
25369 Smallstr200_Print(row.nextfile, temp);
25370 str << " -nextfile:";
25371 strptr_PrintBash(temp,str);
25372 }
25373 if (!(row.other == false)) {
25374 ch_RemoveAll(temp);
25375 bool_Print(row.other, temp);
25376 str << " -other:";
25377 strptr_PrintBash(temp,str);
25378 }
25379 if (!(row.updateproto == false)) {
25380 ch_RemoveAll(temp);
25381 bool_Print(row.updateproto, temp);
25382 str << " -updateproto:";
25383 strptr_PrintBash(temp,str);
25384 }
25385 if (!(row.listfunc == false)) {
25386 ch_RemoveAll(temp);
25387 bool_Print(row.listfunc, temp);
25388 str << " -listfunc:";
25389 strptr_PrintBash(temp,str);
25390 }
25391 if (!(row.iffy == false)) {
25392 ch_RemoveAll(temp);
25393 bool_Print(row.iffy, temp);
25394 str << " -iffy:";
25395 strptr_PrintBash(temp,str);
25396 }
25397 if (!(row.proto == false)) {
25398 ch_RemoveAll(temp);
25399 bool_Print(row.proto, temp);
25400 str << " -proto:";
25401 strptr_PrintBash(temp,str);
25402 }
25403 if (!(row.gen == false)) {
25404 ch_RemoveAll(temp);
25405 bool_Print(row.gen, temp);
25406 str << " -gen:";
25407 strptr_PrintBash(temp,str);
25408 }
25409 if (!(row.showloc == true)) {
25410 ch_RemoveAll(temp);
25411 bool_Print(row.showloc, temp);
25412 str << " -showloc:";
25413 strptr_PrintBash(temp,str);
25414 }
25415 if (!(row.showstatic == true)) {
25416 ch_RemoveAll(temp);
25417 bool_Print(row.showstatic, temp);
25418 str << " -showstatic:";
25419 strptr_PrintBash(temp,str);
25420 }
25421 if (!(row.showsortkey == false)) {
25422 ch_RemoveAll(temp);
25423 bool_Print(row.showsortkey, temp);
25424 str << " -showsortkey:";
25425 strptr_PrintBash(temp,str);
25426 }
25427 if (!(row.sortname == false)) {
25428 ch_RemoveAll(temp);
25429 bool_Print(row.sortname, temp);
25430 str << " -sortname:";
25431 strptr_PrintBash(temp,str);
25432 }
25433 if (!(row.e == false)) {
25434 ch_RemoveAll(temp);
25435 bool_Print(row.e, temp);
25436 str << " -e:";
25437 strptr_PrintBash(temp,str);
25438 }
25439 if (!(row.baddecl == false)) {
25440 ch_RemoveAll(temp);
25441 bool_Print(row.baddecl, temp);
25442 str << " -baddecl:";
25443 strptr_PrintBash(temp,str);
25444 }
25445 if (!(row.report == false)) {
25446 ch_RemoveAll(temp);
25447 bool_Print(row.report, temp);
25448 str << " -report:";
25449 strptr_PrintBash(temp,str);
25450 }
25451}
25452
25453// --- command.src_func..GetAnon
25454algo::strptr command::src_func_GetAnon(command::src_func &parent, i32 idx) {
25455 (void)parent;//only to avoid -Wunused-parameter
25456 switch(idx) {
25457 case(0): return strptr("target", 6);
25458 case(1): return strptr("name", 4);
25459 case(2): return strptr("body", 4);
25460 default: return algo::strptr();
25461 }
25462}
25463
25464// --- command.src_func..NArgs
25465// Used with command lines
25466// Return # of command-line arguments that must follow this argument
25467// If FIELD is invalid, return -1
25468i32 command::src_func_NArgs(command::FieldId field, algo::strptr& out_dflt, bool* out_anon) {
25469 i32 retval = 1;
25470 switch (field) {
25471 case command_FieldId_in: { // $comment
25472 *out_anon = false;
25473 } break;
25474 case command_FieldId_target: { // $comment
25475 *out_anon = true;
25476 } break;
25477 case command_FieldId_name: { // $comment
25478 *out_anon = true;
25479 } break;
25480 case command_FieldId_body: { // $comment
25481 *out_anon = true;
25482 } break;
25483 case command_FieldId_targsrc: { // $comment
25484 *out_anon = false;
25485 } break;
25486 case command_FieldId_func: { // $comment
25487 *out_anon = false;
25488 } break;
25489 case command_FieldId_comment: { // $comment
25490 *out_anon = false;
25491 } break;
25492 case command_FieldId_nextfile: { // $comment
25493 *out_anon = false;
25494 } break;
25495 case command_FieldId_other: { // $comment
25496 *out_anon = false;
25497 retval=0;
25498 out_dflt="Y";
25499 } break;
25500 case command_FieldId_updateproto: { // bool: no argument required but value may be specified as other:Y
25501 *out_anon = false;
25502 retval=0;
25503 out_dflt="Y";
25504 } break;
25505 case command_FieldId_listfunc: { // bool: no argument required but value may be specified as updateproto:Y
25506 *out_anon = false;
25507 retval=0;
25508 out_dflt="Y";
25509 } break;
25510 case command_FieldId_iffy: { // bool: no argument required but value may be specified as listfunc:Y
25511 *out_anon = false;
25512 retval=0;
25513 out_dflt="Y";
25514 } break;
25515 case command_FieldId_proto: { // bool: no argument required but value may be specified as iffy:Y
25516 *out_anon = false;
25517 retval=0;
25518 out_dflt="Y";
25519 } break;
25520 case command_FieldId_gen: { // bool: no argument required but value may be specified as proto:Y
25521 *out_anon = false;
25522 retval=0;
25523 out_dflt="Y";
25524 } break;
25525 case command_FieldId_showloc: { // bool: no argument required but value may be specified as gen:Y
25526 *out_anon = false;
25527 retval=0;
25528 out_dflt="Y";
25529 } break;
25530 case command_FieldId_showstatic: { // bool: no argument required but value may be specified as showloc:Y
25531 *out_anon = false;
25532 retval=0;
25533 out_dflt="Y";
25534 } break;
25535 case command_FieldId_showsortkey: { // bool: no argument required but value may be specified as showstatic:Y
25536 *out_anon = false;
25537 retval=0;
25538 out_dflt="Y";
25539 } break;
25540 case command_FieldId_sortname: { // bool: no argument required but value may be specified as showsortkey:Y
25541 *out_anon = false;
25542 retval=0;
25543 out_dflt="Y";
25544 } break;
25545 case command_FieldId_e: { // bool: no argument required but value may be specified as sortname:Y
25546 *out_anon = false;
25547 retval=0;
25548 out_dflt="Y";
25549 } break;
25550 case command_FieldId_baddecl: { // bool: no argument required but value may be specified as e:Y
25551 *out_anon = false;
25552 retval=0;
25553 out_dflt="Y";
25554 } break;
25555 case command_FieldId_report: { // bool: no argument required but value may be specified as baddecl:Y
25556 *out_anon = false;
25557 retval=0;
25558 out_dflt="Y";
25559 } break;
25560 default:
25561 retval=-1; // unrecognized
25562 }
25563 return retval;
25564}
25565
25566// --- command.src_func_proc.src_func.Start
25567// Start subprocess
25568// If subprocess already running, do nothing. Otherwise, start it
25569int command::src_func_Start(command::src_func_proc& parent) {
25570 int retval = 0;
25571 if (parent.pid == 0) {
25572 verblog(src_func_ToCmdline(parent)); // maybe print command
25573#ifdef WIN32
25574 algo_lib::ResolveExecFname(parent.path);
25575 tempstr cmdline(src_func_ToCmdline(parent));
25576 parent.pid = dospawn(Zeroterm(parent.path),Zeroterm(cmdline),parent.timeout,parent.fstdin,parent.fstdout,parent.fstderr);
25577#else
25578 parent.pid = fork();
25579 if (parent.pid == 0) { // child
25580 algo_lib::DieWithParent();
25581 if (parent.timeout > 0) {
25582 alarm(parent.timeout);
25583 }
25584 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstdin , 0);
25585 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstdout, 1);
25586 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstderr, 2);
25587 if (retval==0) retval= src_func_Execv(parent);
25588 if (retval != 0) { // if start fails, print error
25589 int err=errno;
25590 prerr("command.src_func_execv"
25591 <<Keyval("errno",err)
25592 <<Keyval("errstr",strerror(err))
25593 <<Keyval("comment","Execv failed"));
25594 }
25595 _exit(127); // if failed to start, exit anyway
25596 } else if (parent.pid == -1) {
25597 retval = errno; // failed to fork
25598 }
25599#endif
25600 }
25601 parent.status = parent.pid > 0 ? 0 : -1; // if didn't start, set error status
25602 return retval;
25603}
25604
25605// --- command.src_func_proc.src_func.StartRead
25606// Start subprocess & Read output
25607algo::Fildes command::src_func_StartRead(command::src_func_proc& parent, algo_lib::FFildes &read) {
25608 int pipefd[2];
25609 int rc=pipe(pipefd);
25610 (void)rc;
25611 read.fd.value = pipefd[0];
25612 parent.fstdout << ">&" << pipefd[1];
25613 src_func_Start(parent);
25614 (void)close(pipefd[1]);
25615 return read.fd;
25616}
25617
25618// --- command.src_func_proc.src_func.Kill
25619// Kill subprocess and wait
25620void command::src_func_Kill(command::src_func_proc& parent) {
25621 if (parent.pid != 0) {
25622 kill(parent.pid,9);
25623 src_func_Wait(parent);
25624 }
25625}
25626
25627// --- command.src_func_proc.src_func.Wait
25628// Wait for subprocess to return
25629void command::src_func_Wait(command::src_func_proc& parent) {
25630 if (parent.pid > 0) {
25631 int wait_flags = 0;
25632 int wait_status = 0;
25633 int rc = -1;
25634 do {
25635 // really wait for subprocess to exit
25636 rc = waitpid(parent.pid,&wait_status,wait_flags);
25637 } while (rc==-1 && errno==EINTR);
25638 if (rc == parent.pid) {
25639 parent.status = wait_status;
25640 parent.pid = 0;
25641 }
25642 }
25643}
25644
25645// --- command.src_func_proc.src_func.Exec
25646// Start + Wait
25647// Execute subprocess and return exit code
25648int command::src_func_Exec(command::src_func_proc& parent) {
25649 src_func_Start(parent);
25650 src_func_Wait(parent);
25651 return parent.status;
25652}
25653
25654// --- command.src_func_proc.src_func.ExecX
25655// Start + Wait, throw exception on error
25656// Execute subprocess; throw human-readable exception on error
25657void command::src_func_ExecX(command::src_func_proc& parent) {
25658 int rc = src_func_Exec(parent);
25659 vrfy(rc==0, tempstr() << "algo_lib.exec" << Keyval("cmd",src_func_ToCmdline(parent))
25660 << Keyval("comment",algo::DescribeWaitStatus(parent.status)));
25661}
25662
25663// --- command.src_func_proc.src_func.Execv
25664// Call execv()
25665// Call execv with specified parameters
25666int command::src_func_Execv(command::src_func_proc& parent) {
25667 int ret = 0;
25668 algo::StringAry args;
25669 src_func_ToArgv(parent, args);
25670 char **argv = (char**)alloca((ary_N(args)+1)*sizeof(*argv));
25671 ind_beg(algo::StringAry_ary_curs,arg,args) {
25672 argv[ind_curs(arg).index] = Zeroterm(arg);
25673 }ind_end;
25674 argv[ary_N(args)] = NULL;
25675 // if parent.path is relative, search for it in PATH
25676 algo_lib::ResolveExecFname(parent.path);
25677 ret = execv(Zeroterm(parent.path),argv);
25678 return ret;
25679}
25680
25681// --- command.src_func_proc.src_func.ToCmdline
25682algo::tempstr command::src_func_ToCmdline(command::src_func_proc& parent) {
25683 algo::tempstr retval;
25684 retval << parent.path << " ";
25685 command::src_func_PrintArgv(parent.cmd,retval);
25686 if (ch_N(parent.fstdin)) {
25687 retval << " " << parent.fstdin;
25688 }
25689 if (ch_N(parent.fstdout)) {
25690 retval << " " << parent.fstdout;
25691 }
25692 if (ch_N(parent.fstderr)) {
25693 retval << " 2" << parent.fstderr;
25694 }
25695 return retval;
25696}
25697
25698// --- command.src_func_proc.src_func.ToArgv
25699// Form array from the command line
25700void command::src_func_ToArgv(command::src_func_proc& parent, algo::StringAry& args) {
25701 ary_RemoveAll(args);
25702 ary_Alloc(args) << parent.path;
25703
25704 if (parent.cmd.in != "data") {
25705 cstring *arg = &ary_Alloc(args);
25706 *arg << "-in:";
25707 cstring_Print(parent.cmd.in, *arg);
25708 }
25709
25710 if (parent.cmd.target.expr != "%") {
25711 cstring *arg = &ary_Alloc(args);
25712 *arg << "-target:";
25713 command::target_Print(parent.cmd, *arg);
25714 }
25715
25716 if (parent.cmd.name.expr != "%") {
25717 cstring *arg = &ary_Alloc(args);
25718 *arg << "-name:";
25719 command::name_Print(parent.cmd, *arg);
25720 }
25721
25722 if (parent.cmd.body.expr != "%") {
25723 cstring *arg = &ary_Alloc(args);
25724 *arg << "-body:";
25725 command::body_Print(parent.cmd, *arg);
25726 }
25727
25728 if (parent.cmd.targsrc.expr != "") {
25729 cstring *arg = &ary_Alloc(args);
25730 *arg << "-targsrc:";
25731 command::targsrc_Print(parent.cmd, *arg);
25732 }
25733
25734 if (parent.cmd.func.expr != "%") {
25735 cstring *arg = &ary_Alloc(args);
25736 *arg << "-func:";
25737 command::func_Print(parent.cmd, *arg);
25738 }
25739
25740 if (parent.cmd.comment.expr != "%") {
25741 cstring *arg = &ary_Alloc(args);
25742 *arg << "-comment:";
25743 command::comment_Print(parent.cmd, *arg);
25744 }
25745
25746 if (parent.cmd.nextfile != "") {
25747 cstring *arg = &ary_Alloc(args);
25748 *arg << "-nextfile:";
25749 Smallstr200_Print(parent.cmd.nextfile, *arg);
25750 }
25751
25752 if (parent.cmd.other != false) {
25753 cstring *arg = &ary_Alloc(args);
25754 *arg << "-other:";
25755 bool_Print(parent.cmd.other, *arg);
25756 }
25757
25758 if (parent.cmd.updateproto != false) {
25759 cstring *arg = &ary_Alloc(args);
25760 *arg << "-updateproto:";
25761 bool_Print(parent.cmd.updateproto, *arg);
25762 }
25763
25764 if (parent.cmd.listfunc != false) {
25765 cstring *arg = &ary_Alloc(args);
25766 *arg << "-listfunc:";
25767 bool_Print(parent.cmd.listfunc, *arg);
25768 }
25769
25770 if (parent.cmd.iffy != false) {
25771 cstring *arg = &ary_Alloc(args);
25772 *arg << "-iffy:";
25773 bool_Print(parent.cmd.iffy, *arg);
25774 }
25775
25776 if (parent.cmd.proto != false) {
25777 cstring *arg = &ary_Alloc(args);
25778 *arg << "-proto:";
25779 bool_Print(parent.cmd.proto, *arg);
25780 }
25781
25782 if (parent.cmd.gen != false) {
25783 cstring *arg = &ary_Alloc(args);
25784 *arg << "-gen:";
25785 bool_Print(parent.cmd.gen, *arg);
25786 }
25787
25788 if (parent.cmd.showloc != true) {
25789 cstring *arg = &ary_Alloc(args);
25790 *arg << "-showloc:";
25791 bool_Print(parent.cmd.showloc, *arg);
25792 }
25793
25794 if (parent.cmd.showstatic != true) {
25795 cstring *arg = &ary_Alloc(args);
25796 *arg << "-showstatic:";
25797 bool_Print(parent.cmd.showstatic, *arg);
25798 }
25799
25800 if (parent.cmd.showsortkey != false) {
25801 cstring *arg = &ary_Alloc(args);
25802 *arg << "-showsortkey:";
25803 bool_Print(parent.cmd.showsortkey, *arg);
25804 }
25805
25806 if (parent.cmd.sortname != false) {
25807 cstring *arg = &ary_Alloc(args);
25808 *arg << "-sortname:";
25809 bool_Print(parent.cmd.sortname, *arg);
25810 }
25811
25812 if (parent.cmd.e != false) {
25813 cstring *arg = &ary_Alloc(args);
25814 *arg << "-e:";
25815 bool_Print(parent.cmd.e, *arg);
25816 }
25817
25818 if (parent.cmd.baddecl != false) {
25819 cstring *arg = &ary_Alloc(args);
25820 *arg << "-baddecl:";
25821 bool_Print(parent.cmd.baddecl, *arg);
25822 }
25823
25824 if (parent.cmd.report != false) {
25825 cstring *arg = &ary_Alloc(args);
25826 *arg << "-report:";
25827 bool_Print(parent.cmd.report, *arg);
25828 }
25829 for (int i=1; i < algo_lib::_db.cmdline.verbose; ++i) {
25830 ary_Alloc(args) << "-verbose";
25831 }
25832}
25833
25834// --- command.src_func_proc..Uninit
25835void command::src_func_proc_Uninit(command::src_func_proc& parent) {
25836 command::src_func_proc &row = parent; (void)row;
25837
25838 // command.src_func_proc.src_func.Uninit (Exec) //
25839 src_func_Kill(parent); // kill child, ensure forward progress
25840}
25841
25842// --- command.src_hdr.targsrc.Print
25843// Print back to string
25844void command::targsrc_Print(command::src_hdr& parent, algo::cstring &out) {
25845 Regx_Print(parent.targsrc, out);
25846}
25847
25848// --- command.src_hdr.targsrc.ReadStrptrMaybe
25849// Read Regx from string
25850// Convert string to field. Return success value
25851bool command::targsrc_ReadStrptrMaybe(command::src_hdr& parent, algo::strptr in) {
25852 bool retval = true;
25853 Regx_ReadSql(parent.targsrc, in, true);
25854 return retval;
25855}
25856
25857// --- command.src_hdr.scriptfile.Print
25858// Print back to string
25859void command::scriptfile_Print(command::src_hdr& parent, algo::cstring &out) {
25860 Regx_Print(parent.scriptfile, out);
25861}
25862
25863// --- command.src_hdr.scriptfile.ReadStrptrMaybe
25864// Read Regx from string
25865// Convert string to field. Return success value
25866bool command::scriptfile_ReadStrptrMaybe(command::src_hdr& parent, algo::strptr in) {
25867 bool retval = true;
25868 Regx_ReadSql(parent.scriptfile, in, true);
25869 return retval;
25870}
25871
25872// --- command.src_hdr..ReadFieldMaybe
25873bool command::src_hdr_ReadFieldMaybe(command::src_hdr& parent, algo::strptr field, algo::strptr strval) {
25874 bool retval = true;
25875 command::FieldId field_id;
25876 (void)value_SetStrptrMaybe(field_id,field);
25877 switch(field_id) {
25878 case command_FieldId_in: {
25879 retval = algo::cstring_ReadStrptrMaybe(parent.in, strval);
25880 break;
25881 }
25882 case command_FieldId_targsrc: {
25883 retval = targsrc_ReadStrptrMaybe(parent, strval);
25884 break;
25885 }
25886 case command_FieldId_write: {
25887 retval = bool_ReadStrptrMaybe(parent.write, strval);
25888 break;
25889 }
25890 case command_FieldId_indent: {
25891 retval = bool_ReadStrptrMaybe(parent.indent, strval);
25892 break;
25893 }
25894 case command_FieldId_update_copyright: {
25895 retval = bool_ReadStrptrMaybe(parent.update_copyright, strval);
25896 break;
25897 }
25898 case command_FieldId_scriptfile: {
25899 retval = scriptfile_ReadStrptrMaybe(parent, strval);
25900 break;
25901 }
25902 default: break;
25903 }
25904 if (!retval) {
25905 algo_lib::AppendErrtext("attr",field);
25906 }
25907 return retval;
25908}
25909
25910// --- command.src_hdr..ReadTupleMaybe
25911// Read fields of command::src_hdr from attributes of ascii tuple TUPLE
25912bool command::src_hdr_ReadTupleMaybe(command::src_hdr &parent, algo::Tuple &tuple) {
25913 bool retval = true;
25914 ind_beg(algo::Tuple_attrs_curs,attr,tuple) {
25915 retval = src_hdr_ReadFieldMaybe(parent, attr.name, attr.value);
25916 if (!retval) {
25917 break;
25918 }
25919 }ind_end;
25920 return retval;
25921}
25922
25923// --- command.src_hdr..Init
25924// Set all fields to initial values.
25925void command::src_hdr_Init(command::src_hdr& parent) {
25926 parent.in = algo::strptr("data");
25927 Regx_ReadSql(parent.targsrc, "", true);
25928 parent.write = bool(false);
25929 parent.indent = bool(false);
25930 parent.update_copyright = bool(false);
25931 Regx_ReadSql(parent.scriptfile, "", true);
25932}
25933
25934// --- command.src_hdr..ToCmdline
25935// Convenience function that returns a full command line
25936// Assume command is in a directory called bin
25937tempstr command::src_hdr_ToCmdline(command::src_hdr& row) {
25938 tempstr ret;
25939 ret << "bin/src_hdr ";
25940 src_hdr_PrintArgv(row, ret);
25941 // inherit less intense verbose, debug options
25942 for (int i = 1; i < algo_lib::_db.cmdline.verbose; i++) {
25943 ret << " -verbose";
25944 }
25945 for (int i = 1; i < algo_lib::_db.cmdline.debug; i++) {
25946 ret << " -debug";
25947 }
25948 return ret;
25949}
25950
25951// --- command.src_hdr..PrintArgv
25952// print string representation of ROW to string STR
25953// cfmt:command.src_hdr.Argv printfmt:Tuple
25954void command::src_hdr_PrintArgv(command::src_hdr& row, algo::cstring& str) {
25955 algo::tempstr temp;
25956 (void)temp;
25957 (void)str;
25958 if (!(row.in == "data")) {
25959 ch_RemoveAll(temp);
25960 cstring_Print(row.in, temp);
25961 str << " -in:";
25962 strptr_PrintBash(temp,str);
25963 }
25964 if (!(row.targsrc.expr == "")) {
25965 ch_RemoveAll(temp);
25966 command::targsrc_Print(const_cast<command::src_hdr&>(row), temp);
25967 str << " -targsrc:";
25968 strptr_PrintBash(temp,str);
25969 }
25970 if (!(row.write == false)) {
25971 ch_RemoveAll(temp);
25972 bool_Print(row.write, temp);
25973 str << " -write:";
25974 strptr_PrintBash(temp,str);
25975 }
25976 if (!(row.indent == false)) {
25977 ch_RemoveAll(temp);
25978 bool_Print(row.indent, temp);
25979 str << " -indent:";
25980 strptr_PrintBash(temp,str);
25981 }
25982 if (!(row.update_copyright == false)) {
25983 ch_RemoveAll(temp);
25984 bool_Print(row.update_copyright, temp);
25985 str << " -update_copyright:";
25986 strptr_PrintBash(temp,str);
25987 }
25988 if (!(row.scriptfile.expr == "")) {
25989 ch_RemoveAll(temp);
25990 command::scriptfile_Print(const_cast<command::src_hdr&>(row), temp);
25991 str << " -scriptfile:";
25992 strptr_PrintBash(temp,str);
25993 }
25994}
25995
25996// --- command.src_hdr..NArgs
25997// Used with command lines
25998// Return # of command-line arguments that must follow this argument
25999// If FIELD is invalid, return -1
26000i32 command::src_hdr_NArgs(command::FieldId field, algo::strptr& out_dflt, bool* out_anon) {
26001 i32 retval = 1;
26002 switch (field) {
26003 case command_FieldId_in: { // $comment
26004 *out_anon = false;
26005 } break;
26006 case command_FieldId_targsrc: { // $comment
26007 *out_anon = false;
26008 } break;
26009 case command_FieldId_write: { // $comment
26010 *out_anon = false;
26011 retval=0;
26012 out_dflt="Y";
26013 } break;
26014 case command_FieldId_indent: { // bool: no argument required but value may be specified as write:Y
26015 *out_anon = false;
26016 retval=0;
26017 out_dflt="Y";
26018 } break;
26019 case command_FieldId_update_copyright: { // bool: no argument required but value may be specified as indent:Y
26020 *out_anon = false;
26021 retval=0;
26022 out_dflt="Y";
26023 } break;
26024 case command_FieldId_scriptfile: { // bool: no argument required but value may be specified as update_copyright:Y
26025 *out_anon = false;
26026 } break;
26027 default:
26028 retval=-1; // unrecognized
26029 }
26030 return retval;
26031}
26032
26033// --- command.src_hdr_proc.src_hdr.Start
26034// Start subprocess
26035// If subprocess already running, do nothing. Otherwise, start it
26036int command::src_hdr_Start(command::src_hdr_proc& parent) {
26037 int retval = 0;
26038 if (parent.pid == 0) {
26039 verblog(src_hdr_ToCmdline(parent)); // maybe print command
26040#ifdef WIN32
26041 algo_lib::ResolveExecFname(parent.path);
26042 tempstr cmdline(src_hdr_ToCmdline(parent));
26043 parent.pid = dospawn(Zeroterm(parent.path),Zeroterm(cmdline),parent.timeout,parent.fstdin,parent.fstdout,parent.fstderr);
26044#else
26045 parent.pid = fork();
26046 if (parent.pid == 0) { // child
26047 algo_lib::DieWithParent();
26048 if (parent.timeout > 0) {
26049 alarm(parent.timeout);
26050 }
26051 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstdin , 0);
26052 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstdout, 1);
26053 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstderr, 2);
26054 if (retval==0) retval= src_hdr_Execv(parent);
26055 if (retval != 0) { // if start fails, print error
26056 int err=errno;
26057 prerr("command.src_hdr_execv"
26058 <<Keyval("errno",err)
26059 <<Keyval("errstr",strerror(err))
26060 <<Keyval("comment","Execv failed"));
26061 }
26062 _exit(127); // if failed to start, exit anyway
26063 } else if (parent.pid == -1) {
26064 retval = errno; // failed to fork
26065 }
26066#endif
26067 }
26068 parent.status = parent.pid > 0 ? 0 : -1; // if didn't start, set error status
26069 return retval;
26070}
26071
26072// --- command.src_hdr_proc.src_hdr.StartRead
26073// Start subprocess & Read output
26074algo::Fildes command::src_hdr_StartRead(command::src_hdr_proc& parent, algo_lib::FFildes &read) {
26075 int pipefd[2];
26076 int rc=pipe(pipefd);
26077 (void)rc;
26078 read.fd.value = pipefd[0];
26079 parent.fstdout << ">&" << pipefd[1];
26080 src_hdr_Start(parent);
26081 (void)close(pipefd[1]);
26082 return read.fd;
26083}
26084
26085// --- command.src_hdr_proc.src_hdr.Kill
26086// Kill subprocess and wait
26087void command::src_hdr_Kill(command::src_hdr_proc& parent) {
26088 if (parent.pid != 0) {
26089 kill(parent.pid,9);
26090 src_hdr_Wait(parent);
26091 }
26092}
26093
26094// --- command.src_hdr_proc.src_hdr.Wait
26095// Wait for subprocess to return
26096void command::src_hdr_Wait(command::src_hdr_proc& parent) {
26097 if (parent.pid > 0) {
26098 int wait_flags = 0;
26099 int wait_status = 0;
26100 int rc = -1;
26101 do {
26102 // really wait for subprocess to exit
26103 rc = waitpid(parent.pid,&wait_status,wait_flags);
26104 } while (rc==-1 && errno==EINTR);
26105 if (rc == parent.pid) {
26106 parent.status = wait_status;
26107 parent.pid = 0;
26108 }
26109 }
26110}
26111
26112// --- command.src_hdr_proc.src_hdr.Exec
26113// Start + Wait
26114// Execute subprocess and return exit code
26115int command::src_hdr_Exec(command::src_hdr_proc& parent) {
26116 src_hdr_Start(parent);
26117 src_hdr_Wait(parent);
26118 return parent.status;
26119}
26120
26121// --- command.src_hdr_proc.src_hdr.ExecX
26122// Start + Wait, throw exception on error
26123// Execute subprocess; throw human-readable exception on error
26124void command::src_hdr_ExecX(command::src_hdr_proc& parent) {
26125 int rc = src_hdr_Exec(parent);
26126 vrfy(rc==0, tempstr() << "algo_lib.exec" << Keyval("cmd",src_hdr_ToCmdline(parent))
26127 << Keyval("comment",algo::DescribeWaitStatus(parent.status)));
26128}
26129
26130// --- command.src_hdr_proc.src_hdr.Execv
26131// Call execv()
26132// Call execv with specified parameters
26133int command::src_hdr_Execv(command::src_hdr_proc& parent) {
26134 int ret = 0;
26135 algo::StringAry args;
26136 src_hdr_ToArgv(parent, args);
26137 char **argv = (char**)alloca((ary_N(args)+1)*sizeof(*argv));
26138 ind_beg(algo::StringAry_ary_curs,arg,args) {
26139 argv[ind_curs(arg).index] = Zeroterm(arg);
26140 }ind_end;
26141 argv[ary_N(args)] = NULL;
26142 // if parent.path is relative, search for it in PATH
26143 algo_lib::ResolveExecFname(parent.path);
26144 ret = execv(Zeroterm(parent.path),argv);
26145 return ret;
26146}
26147
26148// --- command.src_hdr_proc.src_hdr.ToCmdline
26149algo::tempstr command::src_hdr_ToCmdline(command::src_hdr_proc& parent) {
26150 algo::tempstr retval;
26151 retval << parent.path << " ";
26152 command::src_hdr_PrintArgv(parent.cmd,retval);
26153 if (ch_N(parent.fstdin)) {
26154 retval << " " << parent.fstdin;
26155 }
26156 if (ch_N(parent.fstdout)) {
26157 retval << " " << parent.fstdout;
26158 }
26159 if (ch_N(parent.fstderr)) {
26160 retval << " 2" << parent.fstderr;
26161 }
26162 return retval;
26163}
26164
26165// --- command.src_hdr_proc.src_hdr.ToArgv
26166// Form array from the command line
26167void command::src_hdr_ToArgv(command::src_hdr_proc& parent, algo::StringAry& args) {
26168 ary_RemoveAll(args);
26169 ary_Alloc(args) << parent.path;
26170
26171 if (parent.cmd.in != "data") {
26172 cstring *arg = &ary_Alloc(args);
26173 *arg << "-in:";
26174 cstring_Print(parent.cmd.in, *arg);
26175 }
26176
26177 if (parent.cmd.targsrc.expr != "") {
26178 cstring *arg = &ary_Alloc(args);
26179 *arg << "-targsrc:";
26180 command::targsrc_Print(parent.cmd, *arg);
26181 }
26182
26183 if (parent.cmd.write != false) {
26184 cstring *arg = &ary_Alloc(args);
26185 *arg << "-write:";
26186 bool_Print(parent.cmd.write, *arg);
26187 }
26188
26189 if (parent.cmd.indent != false) {
26190 cstring *arg = &ary_Alloc(args);
26191 *arg << "-indent:";
26192 bool_Print(parent.cmd.indent, *arg);
26193 }
26194
26195 if (parent.cmd.update_copyright != false) {
26196 cstring *arg = &ary_Alloc(args);
26197 *arg << "-update_copyright:";
26198 bool_Print(parent.cmd.update_copyright, *arg);
26199 }
26200
26201 if (parent.cmd.scriptfile.expr != "") {
26202 cstring *arg = &ary_Alloc(args);
26203 *arg << "-scriptfile:";
26204 command::scriptfile_Print(parent.cmd, *arg);
26205 }
26206 for (int i=1; i < algo_lib::_db.cmdline.verbose; ++i) {
26207 ary_Alloc(args) << "-verbose";
26208 }
26209}
26210
26211// --- command.src_hdr_proc..Uninit
26212void command::src_hdr_proc_Uninit(command::src_hdr_proc& parent) {
26213 command::src_hdr_proc &row = parent; (void)row;
26214
26215 // command.src_hdr_proc.src_hdr.Uninit (Exec) //
26216 src_hdr_Kill(parent); // kill child, ensure forward progress
26217}
26218
26219// --- command.src_lim.srcfile.Print
26220// Print back to string
26221void command::srcfile_Print(command::src_lim& parent, algo::cstring &out) {
26222 Regx_Print(parent.srcfile, out);
26223}
26224
26225// --- command.src_lim.srcfile.ReadStrptrMaybe
26226// Read Regx from string
26227// Convert string to field. Return success value
26228bool command::srcfile_ReadStrptrMaybe(command::src_lim& parent, algo::strptr in) {
26229 bool retval = true;
26230 Regx_ReadSql(parent.srcfile, in, true);
26231 return retval;
26232}
26233
26234// --- command.src_lim.badline.Print
26235// Print back to string
26236void command::badline_Print(command::src_lim& parent, algo::cstring &out) {
26237 Regx_Print(parent.badline, out);
26238}
26239
26240// --- command.src_lim.badline.ReadStrptrMaybe
26241// Read Regx from string
26242// Convert string to field. Return success value
26243bool command::badline_ReadStrptrMaybe(command::src_lim& parent, algo::strptr in) {
26244 bool retval = true;
26245 Regx_ReadSql(parent.badline, in, true);
26246 return retval;
26247}
26248
26249// --- command.src_lim..ReadFieldMaybe
26250bool command::src_lim_ReadFieldMaybe(command::src_lim& parent, algo::strptr field, algo::strptr strval) {
26251 bool retval = true;
26252 command::FieldId field_id;
26253 (void)value_SetStrptrMaybe(field_id,field);
26254 switch(field_id) {
26255 case command_FieldId_in: {
26256 retval = algo::cstring_ReadStrptrMaybe(parent.in, strval);
26257 break;
26258 }
26259 case command_FieldId_linelim: {
26260 retval = bool_ReadStrptrMaybe(parent.linelim, strval);
26261 break;
26262 }
26263 case command_FieldId_srcfile: {
26264 retval = srcfile_ReadStrptrMaybe(parent, strval);
26265 break;
26266 }
26267 case command_FieldId_strayfile: {
26268 retval = bool_ReadStrptrMaybe(parent.strayfile, strval);
26269 break;
26270 }
26271 case command_FieldId_capture: {
26272 retval = bool_ReadStrptrMaybe(parent.capture, strval);
26273 break;
26274 }
26275 case command_FieldId_write: {
26276 retval = bool_ReadStrptrMaybe(parent.write, strval);
26277 break;
26278 }
26279 case command_FieldId_badchar: {
26280 retval = bool_ReadStrptrMaybe(parent.badchar, strval);
26281 break;
26282 }
26283 case command_FieldId_badline: {
26284 retval = badline_ReadStrptrMaybe(parent, strval);
26285 break;
26286 }
26287 default: break;
26288 }
26289 if (!retval) {
26290 algo_lib::AppendErrtext("attr",field);
26291 }
26292 return retval;
26293}
26294
26295// --- command.src_lim..ReadTupleMaybe
26296// Read fields of command::src_lim from attributes of ascii tuple TUPLE
26297bool command::src_lim_ReadTupleMaybe(command::src_lim &parent, algo::Tuple &tuple) {
26298 bool retval = true;
26299 ind_beg(algo::Tuple_attrs_curs,attr,tuple) {
26300 retval = src_lim_ReadFieldMaybe(parent, attr.name, attr.value);
26301 if (!retval) {
26302 break;
26303 }
26304 }ind_end;
26305 return retval;
26306}
26307
26308// --- command.src_lim..Init
26309// Set all fields to initial values.
26310void command::src_lim_Init(command::src_lim& parent) {
26311 parent.in = algo::strptr("data");
26312 parent.linelim = bool(false);
26313 Regx_ReadSql(parent.srcfile, "%", true);
26314 parent.strayfile = bool(false);
26315 parent.capture = bool(false);
26316 parent.write = bool(false);
26317 parent.badchar = bool(false);
26318 Regx_ReadSql(parent.badline, "", true);
26319}
26320
26321// --- command.src_lim..ToCmdline
26322// Convenience function that returns a full command line
26323// Assume command is in a directory called bin
26324tempstr command::src_lim_ToCmdline(command::src_lim& row) {
26325 tempstr ret;
26326 ret << "bin/src_lim ";
26327 src_lim_PrintArgv(row, ret);
26328 // inherit less intense verbose, debug options
26329 for (int i = 1; i < algo_lib::_db.cmdline.verbose; i++) {
26330 ret << " -verbose";
26331 }
26332 for (int i = 1; i < algo_lib::_db.cmdline.debug; i++) {
26333 ret << " -debug";
26334 }
26335 return ret;
26336}
26337
26338// --- command.src_lim..PrintArgv
26339// print string representation of ROW to string STR
26340// cfmt:command.src_lim.Argv printfmt:Tuple
26341void command::src_lim_PrintArgv(command::src_lim& row, algo::cstring& str) {
26342 algo::tempstr temp;
26343 (void)temp;
26344 (void)str;
26345 if (!(row.in == "data")) {
26346 ch_RemoveAll(temp);
26347 cstring_Print(row.in, temp);
26348 str << " -in:";
26349 strptr_PrintBash(temp,str);
26350 }
26351 if (!(row.linelim == false)) {
26352 ch_RemoveAll(temp);
26353 bool_Print(row.linelim, temp);
26354 str << " -linelim:";
26355 strptr_PrintBash(temp,str);
26356 }
26357 if (!(row.srcfile.expr == "%")) {
26358 ch_RemoveAll(temp);
26359 command::srcfile_Print(const_cast<command::src_lim&>(row), temp);
26360 str << " -srcfile:";
26361 strptr_PrintBash(temp,str);
26362 }
26363 if (!(row.strayfile == false)) {
26364 ch_RemoveAll(temp);
26365 bool_Print(row.strayfile, temp);
26366 str << " -strayfile:";
26367 strptr_PrintBash(temp,str);
26368 }
26369 if (!(row.capture == false)) {
26370 ch_RemoveAll(temp);
26371 bool_Print(row.capture, temp);
26372 str << " -capture:";
26373 strptr_PrintBash(temp,str);
26374 }
26375 if (!(row.write == false)) {
26376 ch_RemoveAll(temp);
26377 bool_Print(row.write, temp);
26378 str << " -write:";
26379 strptr_PrintBash(temp,str);
26380 }
26381 if (!(row.badchar == false)) {
26382 ch_RemoveAll(temp);
26383 bool_Print(row.badchar, temp);
26384 str << " -badchar:";
26385 strptr_PrintBash(temp,str);
26386 }
26387 if (!(row.badline.expr == "")) {
26388 ch_RemoveAll(temp);
26389 command::badline_Print(const_cast<command::src_lim&>(row), temp);
26390 str << " -badline:";
26391 strptr_PrintBash(temp,str);
26392 }
26393}
26394
26395// --- command.src_lim..NArgs
26396// Used with command lines
26397// Return # of command-line arguments that must follow this argument
26398// If FIELD is invalid, return -1
26399i32 command::src_lim_NArgs(command::FieldId field, algo::strptr& out_dflt, bool* out_anon) {
26400 i32 retval = 1;
26401 switch (field) {
26402 case command_FieldId_in: { // $comment
26403 *out_anon = false;
26404 } break;
26405 case command_FieldId_linelim: { // $comment
26406 *out_anon = false;
26407 retval=0;
26408 out_dflt="Y";
26409 } break;
26410 case command_FieldId_srcfile: { // bool: no argument required but value may be specified as linelim:Y
26411 *out_anon = false;
26412 } break;
26413 case command_FieldId_strayfile: { // bool: no argument required but value may be specified as linelim:Y
26414 *out_anon = false;
26415 retval=0;
26416 out_dflt="Y";
26417 } break;
26418 case command_FieldId_capture: { // bool: no argument required but value may be specified as strayfile:Y
26419 *out_anon = false;
26420 retval=0;
26421 out_dflt="Y";
26422 } break;
26423 case command_FieldId_write: { // bool: no argument required but value may be specified as capture:Y
26424 *out_anon = false;
26425 retval=0;
26426 out_dflt="Y";
26427 } break;
26428 case command_FieldId_badchar: { // bool: no argument required but value may be specified as write:Y
26429 *out_anon = false;
26430 retval=0;
26431 out_dflt="Y";
26432 } break;
26433 case command_FieldId_badline: { // bool: no argument required but value may be specified as badchar:Y
26434 *out_anon = false;
26435 } break;
26436 default:
26437 retval=-1; // unrecognized
26438 }
26439 return retval;
26440}
26441
26442// --- command.src_lim_proc.src_lim.Start
26443// Start subprocess
26444// If subprocess already running, do nothing. Otherwise, start it
26445int command::src_lim_Start(command::src_lim_proc& parent) {
26446 int retval = 0;
26447 if (parent.pid == 0) {
26448 verblog(src_lim_ToCmdline(parent)); // maybe print command
26449#ifdef WIN32
26450 algo_lib::ResolveExecFname(parent.path);
26451 tempstr cmdline(src_lim_ToCmdline(parent));
26452 parent.pid = dospawn(Zeroterm(parent.path),Zeroterm(cmdline),parent.timeout,parent.fstdin,parent.fstdout,parent.fstderr);
26453#else
26454 parent.pid = fork();
26455 if (parent.pid == 0) { // child
26456 algo_lib::DieWithParent();
26457 if (parent.timeout > 0) {
26458 alarm(parent.timeout);
26459 }
26460 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstdin , 0);
26461 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstdout, 1);
26462 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstderr, 2);
26463 if (retval==0) retval= src_lim_Execv(parent);
26464 if (retval != 0) { // if start fails, print error
26465 int err=errno;
26466 prerr("command.src_lim_execv"
26467 <<Keyval("errno",err)
26468 <<Keyval("errstr",strerror(err))
26469 <<Keyval("comment","Execv failed"));
26470 }
26471 _exit(127); // if failed to start, exit anyway
26472 } else if (parent.pid == -1) {
26473 retval = errno; // failed to fork
26474 }
26475#endif
26476 }
26477 parent.status = parent.pid > 0 ? 0 : -1; // if didn't start, set error status
26478 return retval;
26479}
26480
26481// --- command.src_lim_proc.src_lim.StartRead
26482// Start subprocess & Read output
26483algo::Fildes command::src_lim_StartRead(command::src_lim_proc& parent, algo_lib::FFildes &read) {
26484 int pipefd[2];
26485 int rc=pipe(pipefd);
26486 (void)rc;
26487 read.fd.value = pipefd[0];
26488 parent.fstdout << ">&" << pipefd[1];
26489 src_lim_Start(parent);
26490 (void)close(pipefd[1]);
26491 return read.fd;
26492}
26493
26494// --- command.src_lim_proc.src_lim.Kill
26495// Kill subprocess and wait
26496void command::src_lim_Kill(command::src_lim_proc& parent) {
26497 if (parent.pid != 0) {
26498 kill(parent.pid,9);
26499 src_lim_Wait(parent);
26500 }
26501}
26502
26503// --- command.src_lim_proc.src_lim.Wait
26504// Wait for subprocess to return
26505void command::src_lim_Wait(command::src_lim_proc& parent) {
26506 if (parent.pid > 0) {
26507 int wait_flags = 0;
26508 int wait_status = 0;
26509 int rc = -1;
26510 do {
26511 // really wait for subprocess to exit
26512 rc = waitpid(parent.pid,&wait_status,wait_flags);
26513 } while (rc==-1 && errno==EINTR);
26514 if (rc == parent.pid) {
26515 parent.status = wait_status;
26516 parent.pid = 0;
26517 }
26518 }
26519}
26520
26521// --- command.src_lim_proc.src_lim.Exec
26522// Start + Wait
26523// Execute subprocess and return exit code
26524int command::src_lim_Exec(command::src_lim_proc& parent) {
26525 src_lim_Start(parent);
26526 src_lim_Wait(parent);
26527 return parent.status;
26528}
26529
26530// --- command.src_lim_proc.src_lim.ExecX
26531// Start + Wait, throw exception on error
26532// Execute subprocess; throw human-readable exception on error
26533void command::src_lim_ExecX(command::src_lim_proc& parent) {
26534 int rc = src_lim_Exec(parent);
26535 vrfy(rc==0, tempstr() << "algo_lib.exec" << Keyval("cmd",src_lim_ToCmdline(parent))
26536 << Keyval("comment",algo::DescribeWaitStatus(parent.status)));
26537}
26538
26539// --- command.src_lim_proc.src_lim.Execv
26540// Call execv()
26541// Call execv with specified parameters
26542int command::src_lim_Execv(command::src_lim_proc& parent) {
26543 int ret = 0;
26544 algo::StringAry args;
26545 src_lim_ToArgv(parent, args);
26546 char **argv = (char**)alloca((ary_N(args)+1)*sizeof(*argv));
26547 ind_beg(algo::StringAry_ary_curs,arg,args) {
26548 argv[ind_curs(arg).index] = Zeroterm(arg);
26549 }ind_end;
26550 argv[ary_N(args)] = NULL;
26551 // if parent.path is relative, search for it in PATH
26552 algo_lib::ResolveExecFname(parent.path);
26553 ret = execv(Zeroterm(parent.path),argv);
26554 return ret;
26555}
26556
26557// --- command.src_lim_proc.src_lim.ToCmdline
26558algo::tempstr command::src_lim_ToCmdline(command::src_lim_proc& parent) {
26559 algo::tempstr retval;
26560 retval << parent.path << " ";
26561 command::src_lim_PrintArgv(parent.cmd,retval);
26562 if (ch_N(parent.fstdin)) {
26563 retval << " " << parent.fstdin;
26564 }
26565 if (ch_N(parent.fstdout)) {
26566 retval << " " << parent.fstdout;
26567 }
26568 if (ch_N(parent.fstderr)) {
26569 retval << " 2" << parent.fstderr;
26570 }
26571 return retval;
26572}
26573
26574// --- command.src_lim_proc.src_lim.ToArgv
26575// Form array from the command line
26576void command::src_lim_ToArgv(command::src_lim_proc& parent, algo::StringAry& args) {
26577 ary_RemoveAll(args);
26578 ary_Alloc(args) << parent.path;
26579
26580 if (parent.cmd.in != "data") {
26581 cstring *arg = &ary_Alloc(args);
26582 *arg << "-in:";
26583 cstring_Print(parent.cmd.in, *arg);
26584 }
26585
26586 if (parent.cmd.linelim != false) {
26587 cstring *arg = &ary_Alloc(args);
26588 *arg << "-linelim:";
26589 bool_Print(parent.cmd.linelim, *arg);
26590 }
26591
26592 if (parent.cmd.srcfile.expr != "%") {
26593 cstring *arg = &ary_Alloc(args);
26594 *arg << "-srcfile:";
26595 command::srcfile_Print(parent.cmd, *arg);
26596 }
26597
26598 if (parent.cmd.strayfile != false) {
26599 cstring *arg = &ary_Alloc(args);
26600 *arg << "-strayfile:";
26601 bool_Print(parent.cmd.strayfile, *arg);
26602 }
26603
26604 if (parent.cmd.capture != false) {
26605 cstring *arg = &ary_Alloc(args);
26606 *arg << "-capture:";
26607 bool_Print(parent.cmd.capture, *arg);
26608 }
26609
26610 if (parent.cmd.write != false) {
26611 cstring *arg = &ary_Alloc(args);
26612 *arg << "-write:";
26613 bool_Print(parent.cmd.write, *arg);
26614 }
26615
26616 if (parent.cmd.badchar != false) {
26617 cstring *arg = &ary_Alloc(args);
26618 *arg << "-badchar:";
26619 bool_Print(parent.cmd.badchar, *arg);
26620 }
26621
26622 if (parent.cmd.badline.expr != "") {
26623 cstring *arg = &ary_Alloc(args);
26624 *arg << "-badline:";
26625 command::badline_Print(parent.cmd, *arg);
26626 }
26627 for (int i=1; i < algo_lib::_db.cmdline.verbose; ++i) {
26628 ary_Alloc(args) << "-verbose";
26629 }
26630}
26631
26632// --- command.src_lim_proc..Uninit
26633void command::src_lim_proc_Uninit(command::src_lim_proc& parent) {
26634 command::src_lim_proc &row = parent; (void)row;
26635
26636 // command.src_lim_proc.src_lim.Uninit (Exec) //
26637 src_lim_Kill(parent); // kill child, ensure forward progress
26638}
26639
26640// --- command.ssim2csv..ReadFieldMaybe
26641bool command::ssim2csv_ReadFieldMaybe(command::ssim2csv& parent, algo::strptr field, algo::strptr strval) {
26642 bool retval = true;
26643 command::FieldId field_id;
26644 (void)value_SetStrptrMaybe(field_id,field);
26645 switch(field_id) {
26646 case command_FieldId_expand: {
26647 retval = algo::cstring_ReadStrptrMaybe(parent.expand, strval);
26648 break;
26649 }
26650 case command_FieldId_ignoreQuote: {
26651 retval = bool_ReadStrptrMaybe(parent.ignoreQuote, strval);
26652 break;
26653 }
26654 default: break;
26655 }
26656 if (!retval) {
26657 algo_lib::AppendErrtext("attr",field);
26658 }
26659 return retval;
26660}
26661
26662// --- command.ssim2csv..ReadTupleMaybe
26663// Read fields of command::ssim2csv from attributes of ascii tuple TUPLE
26664bool command::ssim2csv_ReadTupleMaybe(command::ssim2csv &parent, algo::Tuple &tuple) {
26665 bool retval = true;
26666 ind_beg(algo::Tuple_attrs_curs,attr,tuple) {
26667 retval = ssim2csv_ReadFieldMaybe(parent, attr.name, attr.value);
26668 if (!retval) {
26669 break;
26670 }
26671 }ind_end;
26672 return retval;
26673}
26674
26675// --- command.ssim2csv..ToCmdline
26676// Convenience function that returns a full command line
26677// Assume command is in a directory called bin
26678tempstr command::ssim2csv_ToCmdline(command::ssim2csv& row) {
26679 tempstr ret;
26680 ret << "bin/ssim2csv ";
26681 ssim2csv_PrintArgv(row, ret);
26682 // inherit less intense verbose, debug options
26683 for (int i = 1; i < algo_lib::_db.cmdline.verbose; i++) {
26684 ret << " -verbose";
26685 }
26686 for (int i = 1; i < algo_lib::_db.cmdline.debug; i++) {
26687 ret << " -debug";
26688 }
26689 return ret;
26690}
26691
26692// --- command.ssim2csv..PrintArgv
26693// print string representation of ROW to string STR
26694// cfmt:command.ssim2csv.Argv printfmt:Auto
26695void command::ssim2csv_PrintArgv(command::ssim2csv& row, algo::cstring& str) {
26696 algo::tempstr temp;
26697 (void)temp;
26698 (void)str;
26699 if (!(row.expand == "")) {
26700 ch_RemoveAll(temp);
26701 cstring_Print(row.expand, temp);
26702 str << " -expand:";
26703 strptr_PrintBash(temp,str);
26704 }
26705 if (!(row.ignoreQuote == false)) {
26706 ch_RemoveAll(temp);
26707 bool_Print(row.ignoreQuote, temp);
26708 str << " -ignoreQuote:";
26709 strptr_PrintBash(temp,str);
26710 }
26711}
26712
26713// --- command.ssim2csv..NArgs
26714// Used with command lines
26715// Return # of command-line arguments that must follow this argument
26716// If FIELD is invalid, return -1
26717i32 command::ssim2csv_NArgs(command::FieldId field, algo::strptr& out_dflt, bool* out_anon) {
26718 i32 retval = 1;
26719 switch (field) {
26720 case command_FieldId_expand: { // $comment
26721 *out_anon = false;
26722 } break;
26723 case command_FieldId_ignoreQuote: { // $comment
26724 *out_anon = false;
26725 retval=0;
26726 out_dflt="Y";
26727 } break;
26728 default:
26729 retval=-1; // unrecognized
26730 }
26731 return retval;
26732}
26733
26734// --- command.ssim2csv_proc.ssim2csv.Start
26735// Start subprocess
26736// If subprocess already running, do nothing. Otherwise, start it
26737int command::ssim2csv_Start(command::ssim2csv_proc& parent) {
26738 int retval = 0;
26739 if (parent.pid == 0) {
26740 verblog(ssim2csv_ToCmdline(parent)); // maybe print command
26741#ifdef WIN32
26742 algo_lib::ResolveExecFname(parent.path);
26743 tempstr cmdline(ssim2csv_ToCmdline(parent));
26744 parent.pid = dospawn(Zeroterm(parent.path),Zeroterm(cmdline),parent.timeout,parent.fstdin,parent.fstdout,parent.fstderr);
26745#else
26746 parent.pid = fork();
26747 if (parent.pid == 0) { // child
26748 algo_lib::DieWithParent();
26749 if (parent.timeout > 0) {
26750 alarm(parent.timeout);
26751 }
26752 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstdin , 0);
26753 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstdout, 1);
26754 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstderr, 2);
26755 if (retval==0) retval= ssim2csv_Execv(parent);
26756 if (retval != 0) { // if start fails, print error
26757 int err=errno;
26758 prerr("command.ssim2csv_execv"
26759 <<Keyval("errno",err)
26760 <<Keyval("errstr",strerror(err))
26761 <<Keyval("comment","Execv failed"));
26762 }
26763 _exit(127); // if failed to start, exit anyway
26764 } else if (parent.pid == -1) {
26765 retval = errno; // failed to fork
26766 }
26767#endif
26768 }
26769 parent.status = parent.pid > 0 ? 0 : -1; // if didn't start, set error status
26770 return retval;
26771}
26772
26773// --- command.ssim2csv_proc.ssim2csv.StartRead
26774// Start subprocess & Read output
26775algo::Fildes command::ssim2csv_StartRead(command::ssim2csv_proc& parent, algo_lib::FFildes &read) {
26776 int pipefd[2];
26777 int rc=pipe(pipefd);
26778 (void)rc;
26779 read.fd.value = pipefd[0];
26780 parent.fstdout << ">&" << pipefd[1];
26781 ssim2csv_Start(parent);
26782 (void)close(pipefd[1]);
26783 return read.fd;
26784}
26785
26786// --- command.ssim2csv_proc.ssim2csv.Kill
26787// Kill subprocess and wait
26788void command::ssim2csv_Kill(command::ssim2csv_proc& parent) {
26789 if (parent.pid != 0) {
26790 kill(parent.pid,9);
26791 ssim2csv_Wait(parent);
26792 }
26793}
26794
26795// --- command.ssim2csv_proc.ssim2csv.Wait
26796// Wait for subprocess to return
26797void command::ssim2csv_Wait(command::ssim2csv_proc& parent) {
26798 if (parent.pid > 0) {
26799 int wait_flags = 0;
26800 int wait_status = 0;
26801 int rc = -1;
26802 do {
26803 // really wait for subprocess to exit
26804 rc = waitpid(parent.pid,&wait_status,wait_flags);
26805 } while (rc==-1 && errno==EINTR);
26806 if (rc == parent.pid) {
26807 parent.status = wait_status;
26808 parent.pid = 0;
26809 }
26810 }
26811}
26812
26813// --- command.ssim2csv_proc.ssim2csv.Exec
26814// Start + Wait
26815// Execute subprocess and return exit code
26816int command::ssim2csv_Exec(command::ssim2csv_proc& parent) {
26817 ssim2csv_Start(parent);
26818 ssim2csv_Wait(parent);
26819 return parent.status;
26820}
26821
26822// --- command.ssim2csv_proc.ssim2csv.ExecX
26823// Start + Wait, throw exception on error
26824// Execute subprocess; throw human-readable exception on error
26825void command::ssim2csv_ExecX(command::ssim2csv_proc& parent) {
26826 int rc = ssim2csv_Exec(parent);
26827 vrfy(rc==0, tempstr() << "algo_lib.exec" << Keyval("cmd",ssim2csv_ToCmdline(parent))
26828 << Keyval("comment",algo::DescribeWaitStatus(parent.status)));
26829}
26830
26831// --- command.ssim2csv_proc.ssim2csv.Execv
26832// Call execv()
26833// Call execv with specified parameters
26834int command::ssim2csv_Execv(command::ssim2csv_proc& parent) {
26835 int ret = 0;
26836 algo::StringAry args;
26837 ssim2csv_ToArgv(parent, args);
26838 char **argv = (char**)alloca((ary_N(args)+1)*sizeof(*argv));
26839 ind_beg(algo::StringAry_ary_curs,arg,args) {
26840 argv[ind_curs(arg).index] = Zeroterm(arg);
26841 }ind_end;
26842 argv[ary_N(args)] = NULL;
26843 // if parent.path is relative, search for it in PATH
26844 algo_lib::ResolveExecFname(parent.path);
26845 ret = execv(Zeroterm(parent.path),argv);
26846 return ret;
26847}
26848
26849// --- command.ssim2csv_proc.ssim2csv.ToCmdline
26850algo::tempstr command::ssim2csv_ToCmdline(command::ssim2csv_proc& parent) {
26851 algo::tempstr retval;
26852 retval << parent.path << " ";
26853 command::ssim2csv_PrintArgv(parent.cmd,retval);
26854 if (ch_N(parent.fstdin)) {
26855 retval << " " << parent.fstdin;
26856 }
26857 if (ch_N(parent.fstdout)) {
26858 retval << " " << parent.fstdout;
26859 }
26860 if (ch_N(parent.fstderr)) {
26861 retval << " 2" << parent.fstderr;
26862 }
26863 return retval;
26864}
26865
26866// --- command.ssim2csv_proc.ssim2csv.ToArgv
26867// Form array from the command line
26868void command::ssim2csv_ToArgv(command::ssim2csv_proc& parent, algo::StringAry& args) {
26869 ary_RemoveAll(args);
26870 ary_Alloc(args) << parent.path;
26871
26872 if (parent.cmd.expand != "") {
26873 cstring *arg = &ary_Alloc(args);
26874 *arg << "-expand:";
26875 cstring_Print(parent.cmd.expand, *arg);
26876 }
26877
26878 if (parent.cmd.ignoreQuote != false) {
26879 cstring *arg = &ary_Alloc(args);
26880 *arg << "-ignoreQuote:";
26881 bool_Print(parent.cmd.ignoreQuote, *arg);
26882 }
26883 for (int i=1; i < algo_lib::_db.cmdline.verbose; ++i) {
26884 ary_Alloc(args) << "-verbose";
26885 }
26886}
26887
26888// --- command.ssim2csv_proc..Uninit
26889void command::ssim2csv_proc_Uninit(command::ssim2csv_proc& parent) {
26890 command::ssim2csv_proc &row = parent; (void)row;
26891
26892 // command.ssim2csv_proc.ssim2csv.Uninit (Exec) //
26893 ssim2csv_Kill(parent); // kill child, ensure forward progress
26894}
26895
26896// --- command.ssim2mysql..ReadFieldMaybe
26897bool command::ssim2mysql_ReadFieldMaybe(command::ssim2mysql& parent, algo::strptr field, algo::strptr strval) {
26898 bool retval = true;
26899 command::FieldId field_id;
26900 (void)value_SetStrptrMaybe(field_id,field);
26901 switch(field_id) {
26902 case command_FieldId_url: {
26903 retval = algo::cstring_ReadStrptrMaybe(parent.url, strval);
26904 break;
26905 }
26906 case command_FieldId_data_dir: {
26907 retval = algo::cstring_ReadStrptrMaybe(parent.data_dir, strval);
26908 break;
26909 }
26910 case command_FieldId_maxpacket: {
26911 retval = i32_ReadStrptrMaybe(parent.maxpacket, strval);
26912 break;
26913 }
26914 case command_FieldId_replace: {
26915 retval = bool_ReadStrptrMaybe(parent.replace, strval);
26916 break;
26917 }
26918 case command_FieldId_trunc: {
26919 retval = bool_ReadStrptrMaybe(parent.trunc, strval);
26920 break;
26921 }
26922 case command_FieldId_dry_run: {
26923 retval = bool_ReadStrptrMaybe(parent.dry_run, strval);
26924 break;
26925 }
26926 case command_FieldId_fldfunc: {
26927 retval = bool_ReadStrptrMaybe(parent.fldfunc, strval);
26928 break;
26929 }
26930 case command_FieldId_in: {
26931 retval = algo::cstring_ReadStrptrMaybe(parent.in, strval);
26932 break;
26933 }
26934 case command_FieldId_db: {
26935 retval = algo::cstring_ReadStrptrMaybe(parent.db, strval);
26936 break;
26937 }
26938 case command_FieldId_createdb: {
26939 retval = bool_ReadStrptrMaybe(parent.createdb, strval);
26940 break;
26941 }
26942 case command_FieldId_fkey: {
26943 retval = bool_ReadStrptrMaybe(parent.fkey, strval);
26944 break;
26945 }
26946 default: break;
26947 }
26948 if (!retval) {
26949 algo_lib::AppendErrtext("attr",field);
26950 }
26951 return retval;
26952}
26953
26954// --- command.ssim2mysql..ReadTupleMaybe
26955// Read fields of command::ssim2mysql from attributes of ascii tuple TUPLE
26956bool command::ssim2mysql_ReadTupleMaybe(command::ssim2mysql &parent, algo::Tuple &tuple) {
26957 bool retval = true;
26958 ind_beg(algo::Tuple_attrs_curs,attr,tuple) {
26959 retval = ssim2mysql_ReadFieldMaybe(parent, attr.name, attr.value);
26960 if (!retval) {
26961 break;
26962 }
26963 }ind_end;
26964 return retval;
26965}
26966
26967// --- command.ssim2mysql..Init
26968// Set all fields to initial values.
26969void command::ssim2mysql_Init(command::ssim2mysql& parent) {
26970 parent.url = algo::strptr("");
26971 parent.data_dir = algo::strptr("data");
26972 parent.maxpacket = i32(100000);
26973 parent.replace = bool(true);
26974 parent.trunc = bool(false);
26975 parent.dry_run = bool(false);
26976 parent.fldfunc = bool(false);
26977 parent.in = algo::strptr("-");
26978 parent.db = algo::strptr("");
26979 parent.createdb = bool(false);
26980 parent.fkey = bool(false);
26981}
26982
26983// --- command.ssim2mysql..ToCmdline
26984// Convenience function that returns a full command line
26985// Assume command is in a directory called bin
26986tempstr command::ssim2mysql_ToCmdline(command::ssim2mysql& row) {
26987 tempstr ret;
26988 ret << "bin/ssim2mysql ";
26989 ssim2mysql_PrintArgv(row, ret);
26990 // inherit less intense verbose, debug options
26991 for (int i = 1; i < algo_lib::_db.cmdline.verbose; i++) {
26992 ret << " -verbose";
26993 }
26994 for (int i = 1; i < algo_lib::_db.cmdline.debug; i++) {
26995 ret << " -debug";
26996 }
26997 return ret;
26998}
26999
27000// --- command.ssim2mysql..PrintArgv
27001// print string representation of ROW to string STR
27002// cfmt:command.ssim2mysql.Argv printfmt:Auto
27003void command::ssim2mysql_PrintArgv(command::ssim2mysql& row, algo::cstring& str) {
27004 algo::tempstr temp;
27005 (void)temp;
27006 (void)str;
27007 if (!(row.url == "")) {
27008 ch_RemoveAll(temp);
27009 cstring_Print(row.url, temp);
27010 str << " -url:";
27011 strptr_PrintBash(temp,str);
27012 }
27013 if (!(row.data_dir == "data")) {
27014 ch_RemoveAll(temp);
27015 cstring_Print(row.data_dir, temp);
27016 str << " -data_dir:";
27017 strptr_PrintBash(temp,str);
27018 }
27019 if (!(row.maxpacket == 100000)) {
27020 ch_RemoveAll(temp);
27021 i32_Print(row.maxpacket, temp);
27022 str << " -maxpacket:";
27023 strptr_PrintBash(temp,str);
27024 }
27025 if (!(row.replace == true)) {
27026 ch_RemoveAll(temp);
27027 bool_Print(row.replace, temp);
27028 str << " -replace:";
27029 strptr_PrintBash(temp,str);
27030 }
27031 if (!(row.trunc == false)) {
27032 ch_RemoveAll(temp);
27033 bool_Print(row.trunc, temp);
27034 str << " -trunc:";
27035 strptr_PrintBash(temp,str);
27036 }
27037 if (!(row.dry_run == false)) {
27038 ch_RemoveAll(temp);
27039 bool_Print(row.dry_run, temp);
27040 str << " -dry_run:";
27041 strptr_PrintBash(temp,str);
27042 }
27043 if (!(row.fldfunc == false)) {
27044 ch_RemoveAll(temp);
27045 bool_Print(row.fldfunc, temp);
27046 str << " -fldfunc:";
27047 strptr_PrintBash(temp,str);
27048 }
27049 if (!(row.in == "-")) {
27050 ch_RemoveAll(temp);
27051 cstring_Print(row.in, temp);
27052 str << " -in:";
27053 strptr_PrintBash(temp,str);
27054 }
27055 if (!(row.db == "")) {
27056 ch_RemoveAll(temp);
27057 cstring_Print(row.db, temp);
27058 str << " -db:";
27059 strptr_PrintBash(temp,str);
27060 }
27061 if (!(row.createdb == false)) {
27062 ch_RemoveAll(temp);
27063 bool_Print(row.createdb, temp);
27064 str << " -createdb:";
27065 strptr_PrintBash(temp,str);
27066 }
27067 if (!(row.fkey == false)) {
27068 ch_RemoveAll(temp);
27069 bool_Print(row.fkey, temp);
27070 str << " -fkey:";
27071 strptr_PrintBash(temp,str);
27072 }
27073}
27074
27075// --- command.ssim2mysql..NArgs
27076// Used with command lines
27077// Return # of command-line arguments that must follow this argument
27078// If FIELD is invalid, return -1
27079i32 command::ssim2mysql_NArgs(command::FieldId field, algo::strptr& out_dflt, bool* out_anon) {
27080 i32 retval = 1;
27081 switch (field) {
27082 case command_FieldId_url: { // $comment
27083 *out_anon = false;
27084 } break;
27085 case command_FieldId_data_dir: { // $comment
27086 *out_anon = false;
27087 } break;
27088 case command_FieldId_maxpacket: { // $comment
27089 *out_anon = false;
27090 } break;
27091 case command_FieldId_replace: { // $comment
27092 *out_anon = false;
27093 retval=0;
27094 out_dflt="Y";
27095 } break;
27096 case command_FieldId_trunc: { // bool: no argument required but value may be specified as replace:Y
27097 *out_anon = false;
27098 retval=0;
27099 out_dflt="Y";
27100 } break;
27101 case command_FieldId_dry_run: { // bool: no argument required but value may be specified as trunc:Y
27102 *out_anon = false;
27103 retval=0;
27104 out_dflt="Y";
27105 } break;
27106 case command_FieldId_fldfunc: { // bool: no argument required but value may be specified as dry_run:Y
27107 *out_anon = false;
27108 retval=0;
27109 out_dflt="Y";
27110 } break;
27111 case command_FieldId_in: { // bool: no argument required but value may be specified as fldfunc:Y
27112 *out_anon = false;
27113 } break;
27114 case command_FieldId_db: { // bool: no argument required but value may be specified as fldfunc:Y
27115 *out_anon = false;
27116 } break;
27117 case command_FieldId_createdb: { // bool: no argument required but value may be specified as fldfunc:Y
27118 *out_anon = false;
27119 retval=0;
27120 out_dflt="Y";
27121 } break;
27122 case command_FieldId_fkey: { // bool: no argument required but value may be specified as createdb:Y
27123 *out_anon = false;
27124 retval=0;
27125 out_dflt="Y";
27126 } break;
27127 default:
27128 retval=-1; // unrecognized
27129 }
27130 return retval;
27131}
27132
27133// --- command.ssim2mysql_proc.ssim2mysql.Start
27134// Start subprocess
27135// If subprocess already running, do nothing. Otherwise, start it
27136int command::ssim2mysql_Start(command::ssim2mysql_proc& parent) {
27137 int retval = 0;
27138 if (parent.pid == 0) {
27139 verblog(ssim2mysql_ToCmdline(parent)); // maybe print command
27140#ifdef WIN32
27141 algo_lib::ResolveExecFname(parent.path);
27142 tempstr cmdline(ssim2mysql_ToCmdline(parent));
27143 parent.pid = dospawn(Zeroterm(parent.path),Zeroterm(cmdline),parent.timeout,parent.fstdin,parent.fstdout,parent.fstderr);
27144#else
27145 parent.pid = fork();
27146 if (parent.pid == 0) { // child
27147 algo_lib::DieWithParent();
27148 if (parent.timeout > 0) {
27149 alarm(parent.timeout);
27150 }
27151 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstdin , 0);
27152 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstdout, 1);
27153 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstderr, 2);
27154 if (retval==0) retval= ssim2mysql_Execv(parent);
27155 if (retval != 0) { // if start fails, print error
27156 int err=errno;
27157 prerr("command.ssim2mysql_execv"
27158 <<Keyval("errno",err)
27159 <<Keyval("errstr",strerror(err))
27160 <<Keyval("comment","Execv failed"));
27161 }
27162 _exit(127); // if failed to start, exit anyway
27163 } else if (parent.pid == -1) {
27164 retval = errno; // failed to fork
27165 }
27166#endif
27167 }
27168 parent.status = parent.pid > 0 ? 0 : -1; // if didn't start, set error status
27169 return retval;
27170}
27171
27172// --- command.ssim2mysql_proc.ssim2mysql.StartRead
27173// Start subprocess & Read output
27174algo::Fildes command::ssim2mysql_StartRead(command::ssim2mysql_proc& parent, algo_lib::FFildes &read) {
27175 int pipefd[2];
27176 int rc=pipe(pipefd);
27177 (void)rc;
27178 read.fd.value = pipefd[0];
27179 parent.fstdout << ">&" << pipefd[1];
27180 ssim2mysql_Start(parent);
27181 (void)close(pipefd[1]);
27182 return read.fd;
27183}
27184
27185// --- command.ssim2mysql_proc.ssim2mysql.Kill
27186// Kill subprocess and wait
27187void command::ssim2mysql_Kill(command::ssim2mysql_proc& parent) {
27188 if (parent.pid != 0) {
27189 kill(parent.pid,9);
27190 ssim2mysql_Wait(parent);
27191 }
27192}
27193
27194// --- command.ssim2mysql_proc.ssim2mysql.Wait
27195// Wait for subprocess to return
27196void command::ssim2mysql_Wait(command::ssim2mysql_proc& parent) {
27197 if (parent.pid > 0) {
27198 int wait_flags = 0;
27199 int wait_status = 0;
27200 int rc = -1;
27201 do {
27202 // really wait for subprocess to exit
27203 rc = waitpid(parent.pid,&wait_status,wait_flags);
27204 } while (rc==-1 && errno==EINTR);
27205 if (rc == parent.pid) {
27206 parent.status = wait_status;
27207 parent.pid = 0;
27208 }
27209 }
27210}
27211
27212// --- command.ssim2mysql_proc.ssim2mysql.Exec
27213// Start + Wait
27214// Execute subprocess and return exit code
27215int command::ssim2mysql_Exec(command::ssim2mysql_proc& parent) {
27216 ssim2mysql_Start(parent);
27217 ssim2mysql_Wait(parent);
27218 return parent.status;
27219}
27220
27221// --- command.ssim2mysql_proc.ssim2mysql.ExecX
27222// Start + Wait, throw exception on error
27223// Execute subprocess; throw human-readable exception on error
27224void command::ssim2mysql_ExecX(command::ssim2mysql_proc& parent) {
27225 int rc = ssim2mysql_Exec(parent);
27226 vrfy(rc==0, tempstr() << "algo_lib.exec" << Keyval("cmd",ssim2mysql_ToCmdline(parent))
27227 << Keyval("comment",algo::DescribeWaitStatus(parent.status)));
27228}
27229
27230// --- command.ssim2mysql_proc.ssim2mysql.Execv
27231// Call execv()
27232// Call execv with specified parameters
27233int command::ssim2mysql_Execv(command::ssim2mysql_proc& parent) {
27234 int ret = 0;
27235 algo::StringAry args;
27236 ssim2mysql_ToArgv(parent, args);
27237 char **argv = (char**)alloca((ary_N(args)+1)*sizeof(*argv));
27238 ind_beg(algo::StringAry_ary_curs,arg,args) {
27239 argv[ind_curs(arg).index] = Zeroterm(arg);
27240 }ind_end;
27241 argv[ary_N(args)] = NULL;
27242 // if parent.path is relative, search for it in PATH
27243 algo_lib::ResolveExecFname(parent.path);
27244 ret = execv(Zeroterm(parent.path),argv);
27245 return ret;
27246}
27247
27248// --- command.ssim2mysql_proc.ssim2mysql.ToCmdline
27249algo::tempstr command::ssim2mysql_ToCmdline(command::ssim2mysql_proc& parent) {
27250 algo::tempstr retval;
27251 retval << parent.path << " ";
27252 command::ssim2mysql_PrintArgv(parent.cmd,retval);
27253 if (ch_N(parent.fstdin)) {
27254 retval << " " << parent.fstdin;
27255 }
27256 if (ch_N(parent.fstdout)) {
27257 retval << " " << parent.fstdout;
27258 }
27259 if (ch_N(parent.fstderr)) {
27260 retval << " 2" << parent.fstderr;
27261 }
27262 return retval;
27263}
27264
27265// --- command.ssim2mysql_proc.ssim2mysql.ToArgv
27266// Form array from the command line
27267void command::ssim2mysql_ToArgv(command::ssim2mysql_proc& parent, algo::StringAry& args) {
27268 ary_RemoveAll(args);
27269 ary_Alloc(args) << parent.path;
27270
27271 if (parent.cmd.url != "") {
27272 cstring *arg = &ary_Alloc(args);
27273 *arg << "-url:";
27274 cstring_Print(parent.cmd.url, *arg);
27275 }
27276
27277 if (parent.cmd.data_dir != "data") {
27278 cstring *arg = &ary_Alloc(args);
27279 *arg << "-data_dir:";
27280 cstring_Print(parent.cmd.data_dir, *arg);
27281 }
27282
27283 if (parent.cmd.maxpacket != 100000) {
27284 cstring *arg = &ary_Alloc(args);
27285 *arg << "-maxpacket:";
27286 i32_Print(parent.cmd.maxpacket, *arg);
27287 }
27288
27289 if (parent.cmd.replace != true) {
27290 cstring *arg = &ary_Alloc(args);
27291 *arg << "-replace:";
27292 bool_Print(parent.cmd.replace, *arg);
27293 }
27294
27295 if (parent.cmd.trunc != false) {
27296 cstring *arg = &ary_Alloc(args);
27297 *arg << "-trunc:";
27298 bool_Print(parent.cmd.trunc, *arg);
27299 }
27300
27301 if (parent.cmd.dry_run != false) {
27302 cstring *arg = &ary_Alloc(args);
27303 *arg << "-dry_run:";
27304 bool_Print(parent.cmd.dry_run, *arg);
27305 }
27306
27307 if (parent.cmd.fldfunc != false) {
27308 cstring *arg = &ary_Alloc(args);
27309 *arg << "-fldfunc:";
27310 bool_Print(parent.cmd.fldfunc, *arg);
27311 }
27312
27313 if (parent.cmd.in != "-") {
27314 cstring *arg = &ary_Alloc(args);
27315 *arg << "-in:";
27316 cstring_Print(parent.cmd.in, *arg);
27317 }
27318
27319 if (parent.cmd.db != "") {
27320 cstring *arg = &ary_Alloc(args);
27321 *arg << "-db:";
27322 cstring_Print(parent.cmd.db, *arg);
27323 }
27324
27325 if (parent.cmd.createdb != false) {
27326 cstring *arg = &ary_Alloc(args);
27327 *arg << "-createdb:";
27328 bool_Print(parent.cmd.createdb, *arg);
27329 }
27330
27331 if (parent.cmd.fkey != false) {
27332 cstring *arg = &ary_Alloc(args);
27333 *arg << "-fkey:";
27334 bool_Print(parent.cmd.fkey, *arg);
27335 }
27336 for (int i=1; i < algo_lib::_db.cmdline.verbose; ++i) {
27337 ary_Alloc(args) << "-verbose";
27338 }
27339}
27340
27341// --- command.ssim2mysql_proc..Uninit
27342void command::ssim2mysql_proc_Uninit(command::ssim2mysql_proc& parent) {
27343 command::ssim2mysql_proc &row = parent; (void)row;
27344
27345 // command.ssim2mysql_proc.ssim2mysql.Uninit (Exec) //
27346 ssim2mysql_Kill(parent); // kill child, ensure forward progress
27347}
27348
27349// --- command.ssimfilt.typetag.Print
27350// Print back to string
27351void command::typetag_Print(command::ssimfilt& parent, algo::cstring &out) {
27352 Regx_Print(parent.typetag, out);
27353}
27354
27355// --- command.ssimfilt.typetag.ReadStrptrMaybe
27356// Read Regx from string
27357// Convert string to field. Return success value
27358bool command::typetag_ReadStrptrMaybe(command::ssimfilt& parent, algo::strptr in) {
27359 bool retval = true;
27360 Regx_ReadSql(parent.typetag, in, true);
27361 return retval;
27362}
27363
27364// --- command.ssimfilt.match.Addary
27365// Reserve space (this may move memory). Insert N element at the end.
27366// Return aryptr to newly inserted block.
27367// If the RHS argument aliases the array (refers to the same memory), exit program with fatal error.
27368algo::aryptr<algo::cstring> command::match_Addary(command::ssimfilt& parent, algo::aryptr<algo::cstring> rhs) {
27369 bool overlaps = rhs.n_elems>0 && rhs.elems >= parent.match_elems && rhs.elems < parent.match_elems + parent.match_max;
27370 if (UNLIKELY(overlaps)) {
27371 FatalErrorExit("command.tary_alias field:command.ssimfilt.match comment:'alias error: sub-array is being appended to the whole'");
27372 }
27373 int nnew = rhs.n_elems;
27374 match_Reserve(parent, nnew); // reserve space
27375 int at = parent.match_n;
27376 for (int i = 0; i < nnew; i++) {
27377 new (parent.match_elems + at + i) algo::cstring(rhs[i]);
27378 parent.match_n++;
27379 }
27380 return algo::aryptr<algo::cstring>(parent.match_elems + at, nnew);
27381}
27382
27383// --- command.ssimfilt.match.Alloc
27384// Reserve space. Insert element at the end
27385// The new element is initialized to a default value
27386algo::cstring& command::match_Alloc(command::ssimfilt& parent) {
27387 match_Reserve(parent, 1);
27388 int n = parent.match_n;
27389 int at = n;
27390 algo::cstring *elems = parent.match_elems;
27391 new (elems + at) algo::cstring(); // construct new element, default initializer
27392 parent.match_n = n+1;
27393 return elems[at];
27394}
27395
27396// --- command.ssimfilt.match.AllocAt
27397// Reserve space for new element, reallocating the array if necessary
27398// Insert new element at specified index. Index must be in range or a fatal error occurs.
27399algo::cstring& command::match_AllocAt(command::ssimfilt& parent, int at) {
27400 match_Reserve(parent, 1);
27401 int n = parent.match_n;
27402 if (UNLIKELY(u64(at) >= u64(n+1))) {
27403 FatalErrorExit("command.bad_alloc_at field:command.ssimfilt.match comment:'index out of range'");
27404 }
27405 algo::cstring *elems = parent.match_elems;
27406 memmove(elems + at + 1, elems + at, (n - at) * sizeof(algo::cstring));
27407 new (elems + at) algo::cstring(); // construct element, default initializer
27408 parent.match_n = n+1;
27409 return elems[at];
27410}
27411
27412// --- command.ssimfilt.match.AllocN
27413// Reserve space. Insert N elements at the end of the array, return pointer to array
27414algo::aryptr<algo::cstring> command::match_AllocN(command::ssimfilt& parent, int n_elems) {
27415 match_Reserve(parent, n_elems);
27416 int old_n = parent.match_n;
27417 int new_n = old_n + n_elems;
27418 algo::cstring *elems = parent.match_elems;
27419 for (int i = old_n; i < new_n; i++) {
27420 new (elems + i) algo::cstring(); // construct new element, default initialize
27421 }
27422 parent.match_n = new_n;
27423 return algo::aryptr<algo::cstring>(elems + old_n, n_elems);
27424}
27425
27426// --- command.ssimfilt.match.Remove
27427// Remove item by index. If index outside of range, do nothing.
27428void command::match_Remove(command::ssimfilt& parent, u32 i) {
27429 u32 lim = parent.match_n;
27430 algo::cstring *elems = parent.match_elems;
27431 if (i < lim) {
27432 elems[i].~cstring(); // destroy element
27433 memmove(elems + i, elems + (i + 1), sizeof(algo::cstring) * (lim - (i + 1)));
27434 parent.match_n = lim - 1;
27435 }
27436}
27437
27438// --- command.ssimfilt.match.RemoveAll
27439void command::match_RemoveAll(command::ssimfilt& parent) {
27440 u32 n = parent.match_n;
27441 while (n > 0) {
27442 n -= 1;
27443 parent.match_elems[n].~cstring();
27444 parent.match_n = n;
27445 }
27446}
27447
27448// --- command.ssimfilt.match.RemoveLast
27449// Delete last element of array. Do nothing if array is empty.
27450void command::match_RemoveLast(command::ssimfilt& parent) {
27451 u64 n = parent.match_n;
27452 if (n > 0) {
27453 n -= 1;
27454 match_qFind(parent, u64(n)).~cstring();
27455 parent.match_n = n;
27456 }
27457}
27458
27459// --- command.ssimfilt.match.AbsReserve
27460// Make sure N elements fit in array. Process dies if out of memory
27461void command::match_AbsReserve(command::ssimfilt& parent, int n) {
27462 u32 old_max = parent.match_max;
27463 if (n > i32(old_max)) {
27464 u32 new_max = i32_Max(i32_Max(old_max * 2, n), 4);
27465 void *new_mem = algo_lib::malloc_ReallocMem(parent.match_elems, old_max * sizeof(algo::cstring), new_max * sizeof(algo::cstring));
27466 if (UNLIKELY(!new_mem)) {
27467 FatalErrorExit("command.tary_nomem field:command.ssimfilt.match comment:'out of memory'");
27468 }
27469 parent.match_elems = (algo::cstring*)new_mem;
27470 parent.match_max = new_max;
27471 }
27472}
27473
27474// --- command.ssimfilt.match.Setary
27475// Copy contents of RHS to PARENT.
27476void command::match_Setary(command::ssimfilt& parent, command::ssimfilt &rhs) {
27477 match_RemoveAll(parent);
27478 int nnew = rhs.match_n;
27479 match_Reserve(parent, nnew); // reserve space
27480 for (int i = 0; i < nnew; i++) { // copy elements over
27481 new (parent.match_elems + i) algo::cstring(match_qFind(rhs, i));
27482 parent.match_n = i + 1;
27483 }
27484}
27485
27486// --- command.ssimfilt.match.Setary2
27487// Copy specified array into match, discarding previous contents.
27488// If the RHS argument aliases the array (refers to the same memory), throw exception.
27489void command::match_Setary(command::ssimfilt& parent, const algo::aryptr<algo::cstring> &rhs) {
27490 match_RemoveAll(parent);
27491 match_Addary(parent, rhs);
27492}
27493
27494// --- command.ssimfilt.match.AllocNVal
27495// Reserve space. Insert N elements at the end of the array, return pointer to array
27496algo::aryptr<algo::cstring> command::match_AllocNVal(command::ssimfilt& parent, int n_elems, const algo::cstring& val) {
27497 match_Reserve(parent, n_elems);
27498 int old_n = parent.match_n;
27499 int new_n = old_n + n_elems;
27500 algo::cstring *elems = parent.match_elems;
27501 for (int i = old_n; i < new_n; i++) {
27502 new (elems + i) algo::cstring(val);
27503 }
27504 parent.match_n = new_n;
27505 return algo::aryptr<algo::cstring>(elems + old_n, n_elems);
27506}
27507
27508// --- command.ssimfilt.match.ReadStrptrMaybe
27509// A single element is read from input string and appended to the array.
27510// If the string contains an error, the array is untouched.
27511// Function returns success value.
27512bool command::match_ReadStrptrMaybe(command::ssimfilt& parent, algo::strptr in_str) {
27513 bool retval = true;
27514 algo::cstring &elem = match_Alloc(parent);
27515 retval = algo::cstring_ReadStrptrMaybe(elem, in_str);
27516 if (!retval) {
27517 match_RemoveLast(parent);
27518 }
27519 return retval;
27520}
27521
27522// --- command.ssimfilt.field.Addary
27523// Reserve space (this may move memory). Insert N element at the end.
27524// Return aryptr to newly inserted block.
27525// If the RHS argument aliases the array (refers to the same memory), exit program with fatal error.
27526algo::aryptr<algo::cstring> command::field_Addary(command::ssimfilt& parent, algo::aryptr<algo::cstring> rhs) {
27527 bool overlaps = rhs.n_elems>0 && rhs.elems >= parent.field_elems && rhs.elems < parent.field_elems + parent.field_max;
27528 if (UNLIKELY(overlaps)) {
27529 FatalErrorExit("command.tary_alias field:command.ssimfilt.field comment:'alias error: sub-array is being appended to the whole'");
27530 }
27531 int nnew = rhs.n_elems;
27532 field_Reserve(parent, nnew); // reserve space
27533 int at = parent.field_n;
27534 for (int i = 0; i < nnew; i++) {
27535 new (parent.field_elems + at + i) algo::cstring(rhs[i]);
27536 parent.field_n++;
27537 }
27538 return algo::aryptr<algo::cstring>(parent.field_elems + at, nnew);
27539}
27540
27541// --- command.ssimfilt.field.Alloc
27542// Reserve space. Insert element at the end
27543// The new element is initialized to a default value
27544algo::cstring& command::field_Alloc(command::ssimfilt& parent) {
27545 field_Reserve(parent, 1);
27546 int n = parent.field_n;
27547 int at = n;
27548 algo::cstring *elems = parent.field_elems;
27549 new (elems + at) algo::cstring(); // construct new element, default initializer
27550 parent.field_n = n+1;
27551 return elems[at];
27552}
27553
27554// --- command.ssimfilt.field.AllocAt
27555// Reserve space for new element, reallocating the array if necessary
27556// Insert new element at specified index. Index must be in range or a fatal error occurs.
27557algo::cstring& command::field_AllocAt(command::ssimfilt& parent, int at) {
27558 field_Reserve(parent, 1);
27559 int n = parent.field_n;
27560 if (UNLIKELY(u64(at) >= u64(n+1))) {
27561 FatalErrorExit("command.bad_alloc_at field:command.ssimfilt.field comment:'index out of range'");
27562 }
27563 algo::cstring *elems = parent.field_elems;
27564 memmove(elems + at + 1, elems + at, (n - at) * sizeof(algo::cstring));
27565 new (elems + at) algo::cstring(); // construct element, default initializer
27566 parent.field_n = n+1;
27567 return elems[at];
27568}
27569
27570// --- command.ssimfilt.field.AllocN
27571// Reserve space. Insert N elements at the end of the array, return pointer to array
27572algo::aryptr<algo::cstring> command::field_AllocN(command::ssimfilt& parent, int n_elems) {
27573 field_Reserve(parent, n_elems);
27574 int old_n = parent.field_n;
27575 int new_n = old_n + n_elems;
27576 algo::cstring *elems = parent.field_elems;
27577 for (int i = old_n; i < new_n; i++) {
27578 new (elems + i) algo::cstring(); // construct new element, default initialize
27579 }
27580 parent.field_n = new_n;
27581 return algo::aryptr<algo::cstring>(elems + old_n, n_elems);
27582}
27583
27584// --- command.ssimfilt.field.Remove
27585// Remove item by index. If index outside of range, do nothing.
27586void command::field_Remove(command::ssimfilt& parent, u32 i) {
27587 u32 lim = parent.field_n;
27588 algo::cstring *elems = parent.field_elems;
27589 if (i < lim) {
27590 elems[i].~cstring(); // destroy element
27591 memmove(elems + i, elems + (i + 1), sizeof(algo::cstring) * (lim - (i + 1)));
27592 parent.field_n = lim - 1;
27593 }
27594}
27595
27596// --- command.ssimfilt.field.RemoveAll
27597void command::field_RemoveAll(command::ssimfilt& parent) {
27598 u32 n = parent.field_n;
27599 while (n > 0) {
27600 n -= 1;
27601 parent.field_elems[n].~cstring();
27602 parent.field_n = n;
27603 }
27604}
27605
27606// --- command.ssimfilt.field.RemoveLast
27607// Delete last element of array. Do nothing if array is empty.
27608void command::field_RemoveLast(command::ssimfilt& parent) {
27609 u64 n = parent.field_n;
27610 if (n > 0) {
27611 n -= 1;
27612 field_qFind(parent, u64(n)).~cstring();
27613 parent.field_n = n;
27614 }
27615}
27616
27617// --- command.ssimfilt.field.AbsReserve
27618// Make sure N elements fit in array. Process dies if out of memory
27619void command::field_AbsReserve(command::ssimfilt& parent, int n) {
27620 u32 old_max = parent.field_max;
27621 if (n > i32(old_max)) {
27622 u32 new_max = i32_Max(i32_Max(old_max * 2, n), 4);
27623 void *new_mem = algo_lib::malloc_ReallocMem(parent.field_elems, old_max * sizeof(algo::cstring), new_max * sizeof(algo::cstring));
27624 if (UNLIKELY(!new_mem)) {
27625 FatalErrorExit("command.tary_nomem field:command.ssimfilt.field comment:'out of memory'");
27626 }
27627 parent.field_elems = (algo::cstring*)new_mem;
27628 parent.field_max = new_max;
27629 }
27630}
27631
27632// --- command.ssimfilt.field.Setary
27633// Copy contents of RHS to PARENT.
27634void command::field_Setary(command::ssimfilt& parent, command::ssimfilt &rhs) {
27635 field_RemoveAll(parent);
27636 int nnew = rhs.field_n;
27637 field_Reserve(parent, nnew); // reserve space
27638 for (int i = 0; i < nnew; i++) { // copy elements over
27639 new (parent.field_elems + i) algo::cstring(field_qFind(rhs, i));
27640 parent.field_n = i + 1;
27641 }
27642}
27643
27644// --- command.ssimfilt.field.Setary2
27645// Copy specified array into field, discarding previous contents.
27646// If the RHS argument aliases the array (refers to the same memory), throw exception.
27647void command::field_Setary(command::ssimfilt& parent, const algo::aryptr<algo::cstring> &rhs) {
27648 field_RemoveAll(parent);
27649 field_Addary(parent, rhs);
27650}
27651
27652// --- command.ssimfilt.field.AllocNVal
27653// Reserve space. Insert N elements at the end of the array, return pointer to array
27654algo::aryptr<algo::cstring> command::field_AllocNVal(command::ssimfilt& parent, int n_elems, const algo::cstring& val) {
27655 field_Reserve(parent, n_elems);
27656 int old_n = parent.field_n;
27657 int new_n = old_n + n_elems;
27658 algo::cstring *elems = parent.field_elems;
27659 for (int i = old_n; i < new_n; i++) {
27660 new (elems + i) algo::cstring(val);
27661 }
27662 parent.field_n = new_n;
27663 return algo::aryptr<algo::cstring>(elems + old_n, n_elems);
27664}
27665
27666// --- command.ssimfilt.field.ReadStrptrMaybe
27667// A single element is read from input string and appended to the array.
27668// If the string contains an error, the array is untouched.
27669// Function returns success value.
27670bool command::field_ReadStrptrMaybe(command::ssimfilt& parent, algo::strptr in_str) {
27671 bool retval = true;
27672 algo::cstring &elem = field_Alloc(parent);
27673 retval = algo::cstring_ReadStrptrMaybe(elem, in_str);
27674 if (!retval) {
27675 field_RemoveLast(parent);
27676 }
27677 return retval;
27678}
27679
27680// --- command.ssimfilt.format.ToCstr
27681// Convert numeric value of field to one of predefined string constants.
27682// If string is found, return a static C string. Otherwise, return NULL.
27683const char* command::format_ToCstr(const command::ssimfilt& parent) {
27684 const char *ret = NULL;
27685 switch(format_GetEnum(parent)) {
27686 case command_ssimfilt_format_ssim : ret = "ssim"; break;
27687 case command_ssimfilt_format_csv : ret = "csv"; break;
27688 case command_ssimfilt_format_field : ret = "field"; break;
27689 case command_ssimfilt_format_cmd : ret = "cmd"; break;
27690 case command_ssimfilt_format_json : ret = "json"; break;
27691 case command_ssimfilt_format_table : ret = "table"; break;
27692 }
27693 return ret;
27694}
27695
27696// --- command.ssimfilt.format.Print
27697// Convert format to a string. First, attempt conversion to a known string.
27698// If no string matches, print format as a numeric value.
27699void command::format_Print(const command::ssimfilt& parent, algo::cstring &lhs) {
27700 const char *strval = format_ToCstr(parent);
27701 if (strval) {
27702 lhs << strval;
27703 } else {
27704 lhs << parent.format;
27705 }
27706}
27707
27708// --- command.ssimfilt.format.SetStrptrMaybe
27709// Convert string to field.
27710// If the string is invalid, do not modify field and return false.
27711// In case of success, return true
27712bool command::format_SetStrptrMaybe(command::ssimfilt& parent, algo::strptr rhs) {
27713 bool ret = false;
27714 switch (elems_N(rhs)) {
27715 case 3: {
27716 switch (u64(algo::ReadLE16(rhs.elems))|(u64(rhs[2])<<16)) {
27717 case LE_STR3('c','m','d'): {
27718 format_SetEnum(parent,command_ssimfilt_format_cmd); ret = true; break;
27719 }
27720 case LE_STR3('c','s','v'): {
27721 format_SetEnum(parent,command_ssimfilt_format_csv); ret = true; break;
27722 }
27723 }
27724 break;
27725 }
27726 case 4: {
27727 switch (u64(algo::ReadLE32(rhs.elems))) {
27728 case LE_STR4('j','s','o','n'): {
27729 format_SetEnum(parent,command_ssimfilt_format_json); ret = true; break;
27730 }
27731 case LE_STR4('s','s','i','m'): {
27732 format_SetEnum(parent,command_ssimfilt_format_ssim); ret = true; break;
27733 }
27734 }
27735 break;
27736 }
27737 case 5: {
27738 switch (u64(algo::ReadLE32(rhs.elems))|(u64(rhs[4])<<32)) {
27739 case LE_STR5('f','i','e','l','d'): {
27740 format_SetEnum(parent,command_ssimfilt_format_field); ret = true; break;
27741 }
27742 case LE_STR5('t','a','b','l','e'): {
27743 format_SetEnum(parent,command_ssimfilt_format_table); ret = true; break;
27744 }
27745 }
27746 break;
27747 }
27748 }
27749 return ret;
27750}
27751
27752// --- command.ssimfilt.format.SetStrptr
27753// Convert string to field.
27754// If the string is invalid, set numeric value to DFLT
27755void command::format_SetStrptr(command::ssimfilt& parent, algo::strptr rhs, command_ssimfilt_format_Enum dflt) {
27756 if (!format_SetStrptrMaybe(parent,rhs)) format_SetEnum(parent,dflt);
27757}
27758
27759// --- command.ssimfilt.format.ReadStrptrMaybe
27760// Convert string to field. Return success value
27761bool command::format_ReadStrptrMaybe(command::ssimfilt& parent, algo::strptr rhs) {
27762 bool retval = false;
27763 retval = format_SetStrptrMaybe(parent,rhs); // try symbol conversion
27764 if (!retval) { // didn't work? try reading as underlying type
27765 retval = u8_ReadStrptrMaybe(parent.format,rhs);
27766 }
27767 return retval;
27768}
27769
27770// --- command.ssimfilt..ReadFieldMaybe
27771bool command::ssimfilt_ReadFieldMaybe(command::ssimfilt& parent, algo::strptr field, algo::strptr strval) {
27772 bool retval = true;
27773 command::FieldId field_id;
27774 (void)value_SetStrptrMaybe(field_id,algo::Pathcomp(field, ".LL"));
27775 switch(field_id) {
27776 case command_FieldId_in: {
27777 retval = algo::cstring_ReadStrptrMaybe(parent.in, strval);
27778 break;
27779 }
27780 case command_FieldId_typetag: {
27781 retval = typetag_ReadStrptrMaybe(parent, strval);
27782 break;
27783 }
27784 case command_FieldId_match: {
27785 retval = match_ReadStrptrMaybe(parent, strval);
27786 break;
27787 }
27788 case command_FieldId_field: {
27789 retval = field_ReadStrptrMaybe(parent, strval);
27790 break;
27791 }
27792 case command_FieldId_format: {
27793 retval = format_ReadStrptrMaybe(parent, strval);
27794 break;
27795 }
27796 case command_FieldId_t: {
27797 retval = bool_ReadStrptrMaybe(parent.t, strval);
27798 break;
27799 }
27800 case command_FieldId_cmd: {
27801 retval = algo::cstring_ReadStrptrMaybe(parent.cmd, strval);
27802 break;
27803 }
27804 default: break;
27805 }
27806 if (!retval) {
27807 algo_lib::AppendErrtext("attr",field);
27808 }
27809 return retval;
27810}
27811
27812// --- command.ssimfilt..ReadTupleMaybe
27813// Read fields of command::ssimfilt from attributes of ascii tuple TUPLE
27814bool command::ssimfilt_ReadTupleMaybe(command::ssimfilt &parent, algo::Tuple &tuple) {
27815 bool retval = true;
27816 int anon_idx = 0;
27817 ind_beg(algo::Tuple_attrs_curs,attr,tuple) {
27818 if (ch_N(attr.name) == 0) {
27819 attr.name = ssimfilt_GetAnon(parent, anon_idx++);
27820 }
27821 retval = ssimfilt_ReadFieldMaybe(parent, attr.name, attr.value);
27822 if (!retval) {
27823 break;
27824 }
27825 }ind_end;
27826 return retval;
27827}
27828
27829// --- command.ssimfilt..Init
27830// Set all fields to initial values.
27831void command::ssimfilt_Init(command::ssimfilt& parent) {
27832 parent.in = algo::strptr("data");
27833 Regx_ReadSql(parent.typetag, "%", true);
27834 parent.match_elems = 0; // (command.ssimfilt.match)
27835 parent.match_n = 0; // (command.ssimfilt.match)
27836 parent.match_max = 0; // (command.ssimfilt.match)
27837 parent.field_elems = 0; // (command.ssimfilt.field)
27838 parent.field_n = 0; // (command.ssimfilt.field)
27839 parent.field_max = 0; // (command.ssimfilt.field)
27840 parent.format = u8(0);
27841 parent.t = bool(false);
27842 parent.cmd = algo::strptr("");
27843}
27844
27845// --- command.ssimfilt..Uninit
27846void command::ssimfilt_Uninit(command::ssimfilt& parent) {
27847 command::ssimfilt &row = parent; (void)row;
27848
27849 // command.ssimfilt.field.Uninit (Tary) //(project) Select fields for output (regx)
27850 // remove all elements from command.ssimfilt.field
27851 field_RemoveAll(parent);
27852 // free memory for Tary command.ssimfilt.field
27853 algo_lib::malloc_FreeMem(parent.field_elems, sizeof(algo::cstring)*parent.field_max); // (command.ssimfilt.field)
27854
27855 // command.ssimfilt.match.Uninit (Tary) //(filter) Select input tuple if value of key matches value (regx:regx)
27856 // remove all elements from command.ssimfilt.match
27857 match_RemoveAll(parent);
27858 // free memory for Tary command.ssimfilt.match
27859 algo_lib::malloc_FreeMem(parent.match_elems, sizeof(algo::cstring)*parent.match_max); // (command.ssimfilt.match)
27860}
27861
27862// --- command.ssimfilt..ToCmdline
27863// Convenience function that returns a full command line
27864// Assume command is in a directory called bin
27865tempstr command::ssimfilt_ToCmdline(command::ssimfilt& row) {
27866 tempstr ret;
27867 ret << "bin/ssimfilt ";
27868 ssimfilt_PrintArgv(row, ret);
27869 // inherit less intense verbose, debug options
27870 for (int i = 1; i < algo_lib::_db.cmdline.verbose; i++) {
27871 ret << " -verbose";
27872 }
27873 for (int i = 1; i < algo_lib::_db.cmdline.debug; i++) {
27874 ret << " -debug";
27875 }
27876 return ret;
27877}
27878
27879// --- command.ssimfilt..PrintArgv
27880// print string representation of ROW to string STR
27881// cfmt:command.ssimfilt.Argv printfmt:Tuple
27882void command::ssimfilt_PrintArgv(command::ssimfilt& row, algo::cstring& str) {
27883 algo::tempstr temp;
27884 (void)temp;
27885 (void)str;
27886 if (!(row.in == "data")) {
27887 ch_RemoveAll(temp);
27888 cstring_Print(row.in, temp);
27889 str << " -in:";
27890 strptr_PrintBash(temp,str);
27891 }
27892 ch_RemoveAll(temp);
27893 command::typetag_Print(const_cast<command::ssimfilt&>(row), temp);
27894 str << " -typetag:";
27895 strptr_PrintBash(temp,str);
27896 ind_beg(ssimfilt_match_curs,value,row) {
27897 ch_RemoveAll(temp);
27898 cstring_Print(value, temp);
27899 str << " -match:";
27900 strptr_PrintBash(temp,str);
27901 }ind_end;
27902 ind_beg(ssimfilt_field_curs,value,row) {
27903 ch_RemoveAll(temp);
27904 cstring_Print(value, temp);
27905 str << " -field:";
27906 strptr_PrintBash(temp,str);
27907 }ind_end;
27908 if (!(row.format == 0)) {
27909 ch_RemoveAll(temp);
27910 command::format_Print(const_cast<command::ssimfilt&>(row), temp);
27911 str << " -format:";
27912 strptr_PrintBash(temp,str);
27913 }
27914 if (!(row.t == false)) {
27915 ch_RemoveAll(temp);
27916 bool_Print(row.t, temp);
27917 str << " -t:";
27918 strptr_PrintBash(temp,str);
27919 }
27920 if (!(row.cmd == "")) {
27921 ch_RemoveAll(temp);
27922 cstring_Print(row.cmd, temp);
27923 str << " -cmd:";
27924 strptr_PrintBash(temp,str);
27925 }
27926}
27927
27928// --- command.ssimfilt..GetAnon
27929algo::strptr command::ssimfilt_GetAnon(command::ssimfilt &parent, i32 idx) {
27930 (void)parent;//only to avoid -Wunused-parameter
27931 switch(idx) {
27932 case(0): return strptr("typetag", 7);
27933 default: return strptr("match", 5);
27934 }
27935}
27936
27937// --- command.ssimfilt..NArgs
27938// Used with command lines
27939// Return # of command-line arguments that must follow this argument
27940// If FIELD is invalid, return -1
27941i32 command::ssimfilt_NArgs(command::FieldId field, algo::strptr& out_dflt, bool* out_anon) {
27942 i32 retval = 1;
27943 switch (field) {
27944 case command_FieldId_in: { // $comment
27945 *out_anon = false;
27946 } break;
27947 case command_FieldId_typetag: { // $comment
27948 *out_anon = true;
27949 } break;
27950 case command_FieldId_match: { // $comment
27951 *out_anon = true;
27952 } break;
27953 case command_FieldId_field: { // $comment
27954 *out_anon = false;
27955 } break;
27956 case command_FieldId_format: { // $comment
27957 *out_anon = false;
27958 } break;
27959 case command_FieldId_t: { // $comment
27960 *out_anon = false;
27961 retval=0;
27962 out_dflt="Y";
27963 } break;
27964 case command_FieldId_cmd: { // bool: no argument required but value may be specified as t:Y
27965 *out_anon = false;
27966 } break;
27967 default:
27968 retval=-1; // unrecognized
27969 }
27970 return retval;
27971}
27972
27973// --- command.ssimfilt_proc.ssimfilt.Start
27974// Start subprocess
27975// If subprocess already running, do nothing. Otherwise, start it
27976int command::ssimfilt_Start(command::ssimfilt_proc& parent) {
27977 int retval = 0;
27978 if (parent.pid == 0) {
27979 verblog(ssimfilt_ToCmdline(parent)); // maybe print command
27980#ifdef WIN32
27981 algo_lib::ResolveExecFname(parent.path);
27982 tempstr cmdline(ssimfilt_ToCmdline(parent));
27983 parent.pid = dospawn(Zeroterm(parent.path),Zeroterm(cmdline),parent.timeout,parent.fstdin,parent.fstdout,parent.fstderr);
27984#else
27985 parent.pid = fork();
27986 if (parent.pid == 0) { // child
27987 algo_lib::DieWithParent();
27988 if (parent.timeout > 0) {
27989 alarm(parent.timeout);
27990 }
27991 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstdin , 0);
27992 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstdout, 1);
27993 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstderr, 2);
27994 if (retval==0) retval= ssimfilt_Execv(parent);
27995 if (retval != 0) { // if start fails, print error
27996 int err=errno;
27997 prerr("command.ssimfilt_execv"
27998 <<Keyval("errno",err)
27999 <<Keyval("errstr",strerror(err))
28000 <<Keyval("comment","Execv failed"));
28001 }
28002 _exit(127); // if failed to start, exit anyway
28003 } else if (parent.pid == -1) {
28004 retval = errno; // failed to fork
28005 }
28006#endif
28007 }
28008 parent.status = parent.pid > 0 ? 0 : -1; // if didn't start, set error status
28009 return retval;
28010}
28011
28012// --- command.ssimfilt_proc.ssimfilt.StartRead
28013// Start subprocess & Read output
28014algo::Fildes command::ssimfilt_StartRead(command::ssimfilt_proc& parent, algo_lib::FFildes &read) {
28015 int pipefd[2];
28016 int rc=pipe(pipefd);
28017 (void)rc;
28018 read.fd.value = pipefd[0];
28019 parent.fstdout << ">&" << pipefd[1];
28020 ssimfilt_Start(parent);
28021 (void)close(pipefd[1]);
28022 return read.fd;
28023}
28024
28025// --- command.ssimfilt_proc.ssimfilt.Kill
28026// Kill subprocess and wait
28027void command::ssimfilt_Kill(command::ssimfilt_proc& parent) {
28028 if (parent.pid != 0) {
28029 kill(parent.pid,9);
28030 ssimfilt_Wait(parent);
28031 }
28032}
28033
28034// --- command.ssimfilt_proc.ssimfilt.Wait
28035// Wait for subprocess to return
28036void command::ssimfilt_Wait(command::ssimfilt_proc& parent) {
28037 if (parent.pid > 0) {
28038 int wait_flags = 0;
28039 int wait_status = 0;
28040 int rc = -1;
28041 do {
28042 // really wait for subprocess to exit
28043 rc = waitpid(parent.pid,&wait_status,wait_flags);
28044 } while (rc==-1 && errno==EINTR);
28045 if (rc == parent.pid) {
28046 parent.status = wait_status;
28047 parent.pid = 0;
28048 }
28049 }
28050}
28051
28052// --- command.ssimfilt_proc.ssimfilt.Exec
28053// Start + Wait
28054// Execute subprocess and return exit code
28055int command::ssimfilt_Exec(command::ssimfilt_proc& parent) {
28056 ssimfilt_Start(parent);
28057 ssimfilt_Wait(parent);
28058 return parent.status;
28059}
28060
28061// --- command.ssimfilt_proc.ssimfilt.ExecX
28062// Start + Wait, throw exception on error
28063// Execute subprocess; throw human-readable exception on error
28064void command::ssimfilt_ExecX(command::ssimfilt_proc& parent) {
28065 int rc = ssimfilt_Exec(parent);
28066 vrfy(rc==0, tempstr() << "algo_lib.exec" << Keyval("cmd",ssimfilt_ToCmdline(parent))
28067 << Keyval("comment",algo::DescribeWaitStatus(parent.status)));
28068}
28069
28070// --- command.ssimfilt_proc.ssimfilt.Execv
28071// Call execv()
28072// Call execv with specified parameters
28073int command::ssimfilt_Execv(command::ssimfilt_proc& parent) {
28074 int ret = 0;
28075 algo::StringAry args;
28076 ssimfilt_ToArgv(parent, args);
28077 char **argv = (char**)alloca((ary_N(args)+1)*sizeof(*argv));
28078 ind_beg(algo::StringAry_ary_curs,arg,args) {
28079 argv[ind_curs(arg).index] = Zeroterm(arg);
28080 }ind_end;
28081 argv[ary_N(args)] = NULL;
28082 // if parent.path is relative, search for it in PATH
28083 algo_lib::ResolveExecFname(parent.path);
28084 ret = execv(Zeroterm(parent.path),argv);
28085 return ret;
28086}
28087
28088// --- command.ssimfilt_proc.ssimfilt.ToCmdline
28089algo::tempstr command::ssimfilt_ToCmdline(command::ssimfilt_proc& parent) {
28090 algo::tempstr retval;
28091 retval << parent.path << " ";
28092 command::ssimfilt_PrintArgv(parent.cmd,retval);
28093 if (ch_N(parent.fstdin)) {
28094 retval << " " << parent.fstdin;
28095 }
28096 if (ch_N(parent.fstdout)) {
28097 retval << " " << parent.fstdout;
28098 }
28099 if (ch_N(parent.fstderr)) {
28100 retval << " 2" << parent.fstderr;
28101 }
28102 return retval;
28103}
28104
28105// --- command.ssimfilt_proc.ssimfilt.ToArgv
28106// Form array from the command line
28107void command::ssimfilt_ToArgv(command::ssimfilt_proc& parent, algo::StringAry& args) {
28108 ary_RemoveAll(args);
28109 ary_Alloc(args) << parent.path;
28110
28111 if (parent.cmd.in != "data") {
28112 cstring *arg = &ary_Alloc(args);
28113 *arg << "-in:";
28114 cstring_Print(parent.cmd.in, *arg);
28115 }
28116
28117 if (parent.cmd.typetag.expr != "%") {
28118 cstring *arg = &ary_Alloc(args);
28119 *arg << "-typetag:";
28120 command::typetag_Print(parent.cmd, *arg);
28121 }
28122 ind_beg(command::ssimfilt_match_curs,value,parent.cmd) {
28123 cstring *arg = &ary_Alloc(args);
28124 *arg << "-match:";
28125 cstring_Print(value, *arg);
28126 }ind_end;
28127 ind_beg(command::ssimfilt_field_curs,value,parent.cmd) {
28128 cstring *arg = &ary_Alloc(args);
28129 *arg << "-field:";
28130 cstring_Print(value, *arg);
28131 }ind_end;
28132
28133 if (parent.cmd.format != 0) {
28134 cstring *arg = &ary_Alloc(args);
28135 *arg << "-format:";
28136 command::format_Print(parent.cmd, *arg);
28137 }
28138
28139 if (parent.cmd.t != false) {
28140 cstring *arg = &ary_Alloc(args);
28141 *arg << "-t:";
28142 bool_Print(parent.cmd.t, *arg);
28143 }
28144
28145 if (parent.cmd.cmd != "") {
28146 cstring *arg = &ary_Alloc(args);
28147 *arg << "-cmd:";
28148 cstring_Print(parent.cmd.cmd, *arg);
28149 }
28150 for (int i=1; i < algo_lib::_db.cmdline.verbose; ++i) {
28151 ary_Alloc(args) << "-verbose";
28152 }
28153}
28154
28155// --- command.ssimfilt_proc..Uninit
28156void command::ssimfilt_proc_Uninit(command::ssimfilt_proc& parent) {
28157 command::ssimfilt_proc &row = parent; (void)row;
28158
28159 // command.ssimfilt_proc.ssimfilt.Uninit (Exec) //
28160 ssimfilt_Kill(parent); // kill child, ensure forward progress
28161}
28162
28163// --- command.strconv..ReadFieldMaybe
28164bool command::strconv_ReadFieldMaybe(command::strconv& parent, algo::strptr field, algo::strptr strval) {
28165 bool retval = true;
28166 command::FieldId field_id;
28167 (void)value_SetStrptrMaybe(field_id,field);
28168 switch(field_id) {
28169 case command_FieldId_str: {
28170 retval = algo::cstring_ReadStrptrMaybe(parent.str, strval);
28171 break;
28172 }
28173 case command_FieldId_tocamelcase: {
28174 retval = bool_ReadStrptrMaybe(parent.tocamelcase, strval);
28175 break;
28176 }
28177 case command_FieldId_tolowerunder: {
28178 retval = bool_ReadStrptrMaybe(parent.tolowerunder, strval);
28179 break;
28180 }
28181 case command_FieldId_in: {
28182 retval = algo::cstring_ReadStrptrMaybe(parent.in, strval);
28183 break;
28184 }
28185 case command_FieldId_pathcomp: {
28186 retval = algo::Smallstr100_ReadStrptrMaybe(parent.pathcomp, strval);
28187 break;
28188 }
28189 default: break;
28190 }
28191 if (!retval) {
28192 algo_lib::AppendErrtext("attr",field);
28193 }
28194 return retval;
28195}
28196
28197// --- command.strconv..ReadTupleMaybe
28198// Read fields of command::strconv from attributes of ascii tuple TUPLE
28199bool command::strconv_ReadTupleMaybe(command::strconv &parent, algo::Tuple &tuple) {
28200 bool retval = true;
28201 int anon_idx = 0;
28202 ind_beg(algo::Tuple_attrs_curs,attr,tuple) {
28203 if (ch_N(attr.name) == 0) {
28204 attr.name = strconv_GetAnon(parent, anon_idx++);
28205 }
28206 retval = strconv_ReadFieldMaybe(parent, attr.name, attr.value);
28207 if (!retval) {
28208 break;
28209 }
28210 }ind_end;
28211 return retval;
28212}
28213
28214// --- command.strconv..ToCmdline
28215// Convenience function that returns a full command line
28216// Assume command is in a directory called bin
28217tempstr command::strconv_ToCmdline(command::strconv& row) {
28218 tempstr ret;
28219 ret << "bin/strconv ";
28220 strconv_PrintArgv(row, ret);
28221 // inherit less intense verbose, debug options
28222 for (int i = 1; i < algo_lib::_db.cmdline.verbose; i++) {
28223 ret << " -verbose";
28224 }
28225 for (int i = 1; i < algo_lib::_db.cmdline.debug; i++) {
28226 ret << " -debug";
28227 }
28228 return ret;
28229}
28230
28231// --- command.strconv..PrintArgv
28232// print string representation of ROW to string STR
28233// cfmt:command.strconv.Argv printfmt:Tuple
28234void command::strconv_PrintArgv(command::strconv& row, algo::cstring& str) {
28235 algo::tempstr temp;
28236 (void)temp;
28237 (void)str;
28238 ch_RemoveAll(temp);
28239 cstring_Print(row.str, temp);
28240 str << " -str:";
28241 strptr_PrintBash(temp,str);
28242 if (!(row.tocamelcase == false)) {
28243 ch_RemoveAll(temp);
28244 bool_Print(row.tocamelcase, temp);
28245 str << " -tocamelcase:";
28246 strptr_PrintBash(temp,str);
28247 }
28248 if (!(row.tolowerunder == false)) {
28249 ch_RemoveAll(temp);
28250 bool_Print(row.tolowerunder, temp);
28251 str << " -tolowerunder:";
28252 strptr_PrintBash(temp,str);
28253 }
28254 if (!(row.in == "data")) {
28255 ch_RemoveAll(temp);
28256 cstring_Print(row.in, temp);
28257 str << " -in:";
28258 strptr_PrintBash(temp,str);
28259 }
28260 if (!(row.pathcomp == "")) {
28261 ch_RemoveAll(temp);
28262 Smallstr100_Print(row.pathcomp, temp);
28263 str << " -pathcomp:";
28264 strptr_PrintBash(temp,str);
28265 }
28266}
28267
28268// --- command.strconv..GetAnon
28269algo::strptr command::strconv_GetAnon(command::strconv &parent, i32 idx) {
28270 (void)parent;//only to avoid -Wunused-parameter
28271 switch(idx) {
28272 case(0): return strptr("str", 3);
28273 default: return algo::strptr();
28274 }
28275}
28276
28277// --- command.strconv..NArgs
28278// Used with command lines
28279// Return # of command-line arguments that must follow this argument
28280// If FIELD is invalid, return -1
28281i32 command::strconv_NArgs(command::FieldId field, algo::strptr& out_dflt, bool* out_anon) {
28282 i32 retval = 1;
28283 switch (field) {
28284 case command_FieldId_str: { // $comment
28285 *out_anon = true;
28286 } break;
28287 case command_FieldId_tocamelcase: { // $comment
28288 *out_anon = false;
28289 retval=0;
28290 out_dflt="Y";
28291 } break;
28292 case command_FieldId_tolowerunder: { // bool: no argument required but value may be specified as tocamelcase:Y
28293 *out_anon = false;
28294 retval=0;
28295 out_dflt="Y";
28296 } break;
28297 case command_FieldId_in: { // bool: no argument required but value may be specified as tolowerunder:Y
28298 *out_anon = false;
28299 } break;
28300 case command_FieldId_pathcomp: { // bool: no argument required but value may be specified as tolowerunder:Y
28301 *out_anon = false;
28302 } break;
28303 default:
28304 retval=-1; // unrecognized
28305 }
28306 return retval;
28307}
28308
28309// --- command.strconv_proc.strconv.Start
28310// Start subprocess
28311// If subprocess already running, do nothing. Otherwise, start it
28312int command::strconv_Start(command::strconv_proc& parent) {
28313 int retval = 0;
28314 if (parent.pid == 0) {
28315 verblog(strconv_ToCmdline(parent)); // maybe print command
28316#ifdef WIN32
28317 algo_lib::ResolveExecFname(parent.path);
28318 tempstr cmdline(strconv_ToCmdline(parent));
28319 parent.pid = dospawn(Zeroterm(parent.path),Zeroterm(cmdline),parent.timeout,parent.fstdin,parent.fstdout,parent.fstderr);
28320#else
28321 parent.pid = fork();
28322 if (parent.pid == 0) { // child
28323 algo_lib::DieWithParent();
28324 if (parent.timeout > 0) {
28325 alarm(parent.timeout);
28326 }
28327 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstdin , 0);
28328 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstdout, 1);
28329 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstderr, 2);
28330 if (retval==0) retval= strconv_Execv(parent);
28331 if (retval != 0) { // if start fails, print error
28332 int err=errno;
28333 prerr("command.strconv_execv"
28334 <<Keyval("errno",err)
28335 <<Keyval("errstr",strerror(err))
28336 <<Keyval("comment","Execv failed"));
28337 }
28338 _exit(127); // if failed to start, exit anyway
28339 } else if (parent.pid == -1) {
28340 retval = errno; // failed to fork
28341 }
28342#endif
28343 }
28344 parent.status = parent.pid > 0 ? 0 : -1; // if didn't start, set error status
28345 return retval;
28346}
28347
28348// --- command.strconv_proc.strconv.StartRead
28349// Start subprocess & Read output
28350algo::Fildes command::strconv_StartRead(command::strconv_proc& parent, algo_lib::FFildes &read) {
28351 int pipefd[2];
28352 int rc=pipe(pipefd);
28353 (void)rc;
28354 read.fd.value = pipefd[0];
28355 parent.fstdout << ">&" << pipefd[1];
28356 strconv_Start(parent);
28357 (void)close(pipefd[1]);
28358 return read.fd;
28359}
28360
28361// --- command.strconv_proc.strconv.Kill
28362// Kill subprocess and wait
28363void command::strconv_Kill(command::strconv_proc& parent) {
28364 if (parent.pid != 0) {
28365 kill(parent.pid,9);
28366 strconv_Wait(parent);
28367 }
28368}
28369
28370// --- command.strconv_proc.strconv.Wait
28371// Wait for subprocess to return
28372void command::strconv_Wait(command::strconv_proc& parent) {
28373 if (parent.pid > 0) {
28374 int wait_flags = 0;
28375 int wait_status = 0;
28376 int rc = -1;
28377 do {
28378 // really wait for subprocess to exit
28379 rc = waitpid(parent.pid,&wait_status,wait_flags);
28380 } while (rc==-1 && errno==EINTR);
28381 if (rc == parent.pid) {
28382 parent.status = wait_status;
28383 parent.pid = 0;
28384 }
28385 }
28386}
28387
28388// --- command.strconv_proc.strconv.Exec
28389// Start + Wait
28390// Execute subprocess and return exit code
28391int command::strconv_Exec(command::strconv_proc& parent) {
28392 strconv_Start(parent);
28393 strconv_Wait(parent);
28394 return parent.status;
28395}
28396
28397// --- command.strconv_proc.strconv.ExecX
28398// Start + Wait, throw exception on error
28399// Execute subprocess; throw human-readable exception on error
28400void command::strconv_ExecX(command::strconv_proc& parent) {
28401 int rc = strconv_Exec(parent);
28402 vrfy(rc==0, tempstr() << "algo_lib.exec" << Keyval("cmd",strconv_ToCmdline(parent))
28403 << Keyval("comment",algo::DescribeWaitStatus(parent.status)));
28404}
28405
28406// --- command.strconv_proc.strconv.Execv
28407// Call execv()
28408// Call execv with specified parameters
28409int command::strconv_Execv(command::strconv_proc& parent) {
28410 int ret = 0;
28411 algo::StringAry args;
28412 strconv_ToArgv(parent, args);
28413 char **argv = (char**)alloca((ary_N(args)+1)*sizeof(*argv));
28414 ind_beg(algo::StringAry_ary_curs,arg,args) {
28415 argv[ind_curs(arg).index] = Zeroterm(arg);
28416 }ind_end;
28417 argv[ary_N(args)] = NULL;
28418 // if parent.path is relative, search for it in PATH
28419 algo_lib::ResolveExecFname(parent.path);
28420 ret = execv(Zeroterm(parent.path),argv);
28421 return ret;
28422}
28423
28424// --- command.strconv_proc.strconv.ToCmdline
28425algo::tempstr command::strconv_ToCmdline(command::strconv_proc& parent) {
28426 algo::tempstr retval;
28427 retval << parent.path << " ";
28428 command::strconv_PrintArgv(parent.cmd,retval);
28429 if (ch_N(parent.fstdin)) {
28430 retval << " " << parent.fstdin;
28431 }
28432 if (ch_N(parent.fstdout)) {
28433 retval << " " << parent.fstdout;
28434 }
28435 if (ch_N(parent.fstderr)) {
28436 retval << " 2" << parent.fstderr;
28437 }
28438 return retval;
28439}
28440
28441// --- command.strconv_proc.strconv.ToArgv
28442// Form array from the command line
28443void command::strconv_ToArgv(command::strconv_proc& parent, algo::StringAry& args) {
28444 ary_RemoveAll(args);
28445 ary_Alloc(args) << parent.path;
28446
28447 if (true) {
28448 cstring *arg = &ary_Alloc(args);
28449 *arg << "-str:";
28450 cstring_Print(parent.cmd.str, *arg);
28451 }
28452
28453 if (parent.cmd.tocamelcase != false) {
28454 cstring *arg = &ary_Alloc(args);
28455 *arg << "-tocamelcase:";
28456 bool_Print(parent.cmd.tocamelcase, *arg);
28457 }
28458
28459 if (parent.cmd.tolowerunder != false) {
28460 cstring *arg = &ary_Alloc(args);
28461 *arg << "-tolowerunder:";
28462 bool_Print(parent.cmd.tolowerunder, *arg);
28463 }
28464
28465 if (parent.cmd.in != "data") {
28466 cstring *arg = &ary_Alloc(args);
28467 *arg << "-in:";
28468 cstring_Print(parent.cmd.in, *arg);
28469 }
28470
28471 if (parent.cmd.pathcomp != "") {
28472 cstring *arg = &ary_Alloc(args);
28473 *arg << "-pathcomp:";
28474 Smallstr100_Print(parent.cmd.pathcomp, *arg);
28475 }
28476 for (int i=1; i < algo_lib::_db.cmdline.verbose; ++i) {
28477 ary_Alloc(args) << "-verbose";
28478 }
28479}
28480
28481// --- command.strconv_proc..Uninit
28482void command::strconv_proc_Uninit(command::strconv_proc& parent) {
28483 command::strconv_proc &row = parent; (void)row;
28484
28485 // command.strconv_proc.strconv.Uninit (Exec) //
28486 strconv_Kill(parent); // kill child, ensure forward progress
28487}
28488
28489// --- command.sv2ssim.field.Print
28490// Print back to string
28491void command::field_Print(command::sv2ssim& parent, algo::cstring &out) {
28492 Regx_Print(parent.field, out);
28493}
28494
28495// --- command.sv2ssim.field.ReadStrptrMaybe
28496// Read Regx from string
28497// Convert string to field. Return success value
28498bool command::field_ReadStrptrMaybe(command::sv2ssim& parent, algo::strptr in) {
28499 bool retval = true;
28500 Regx_ReadSql(parent.field, in, true);
28501 return retval;
28502}
28503
28504// --- command.sv2ssim..ReadFieldMaybe
28505bool command::sv2ssim_ReadFieldMaybe(command::sv2ssim& parent, algo::strptr field, algo::strptr strval) {
28506 bool retval = true;
28507 command::FieldId field_id;
28508 (void)value_SetStrptrMaybe(field_id,field);
28509 switch(field_id) {
28510 case command_FieldId_in: {
28511 retval = algo::cstring_ReadStrptrMaybe(parent.in, strval);
28512 break;
28513 }
28514 case command_FieldId_fname: {
28515 retval = algo::cstring_ReadStrptrMaybe(parent.fname, strval);
28516 break;
28517 }
28518 case command_FieldId_separator: {
28519 retval = char_ReadStrptrMaybe(parent.separator, strval);
28520 break;
28521 }
28522 case command_FieldId_outseparator: {
28523 retval = algo::cstring_ReadStrptrMaybe(parent.outseparator, strval);
28524 break;
28525 }
28526 case command_FieldId_header: {
28527 retval = bool_ReadStrptrMaybe(parent.header, strval);
28528 break;
28529 }
28530 case command_FieldId_ctype: {
28531 retval = algo::cstring_ReadStrptrMaybe(parent.ctype, strval);
28532 break;
28533 }
28534 case command_FieldId_ssimfile: {
28535 retval = algo::cstring_ReadStrptrMaybe(parent.ssimfile, strval);
28536 break;
28537 }
28538 case command_FieldId_schema: {
28539 retval = bool_ReadStrptrMaybe(parent.schema, strval);
28540 break;
28541 }
28542 case command_FieldId_field: {
28543 retval = field_ReadStrptrMaybe(parent, strval);
28544 break;
28545 }
28546 case command_FieldId_data: {
28547 retval = bool_ReadStrptrMaybe(parent.data, strval);
28548 break;
28549 }
28550 case command_FieldId_report: {
28551 retval = bool_ReadStrptrMaybe(parent.report, strval);
28552 break;
28553 }
28554 case command_FieldId_prefer_signed: {
28555 retval = bool_ReadStrptrMaybe(parent.prefer_signed, strval);
28556 break;
28557 }
28558 default: break;
28559 }
28560 if (!retval) {
28561 algo_lib::AppendErrtext("attr",field);
28562 }
28563 return retval;
28564}
28565
28566// --- command.sv2ssim..ReadTupleMaybe
28567// Read fields of command::sv2ssim from attributes of ascii tuple TUPLE
28568bool command::sv2ssim_ReadTupleMaybe(command::sv2ssim &parent, algo::Tuple &tuple) {
28569 bool retval = true;
28570 int anon_idx = 0;
28571 ind_beg(algo::Tuple_attrs_curs,attr,tuple) {
28572 if (ch_N(attr.name) == 0) {
28573 attr.name = sv2ssim_GetAnon(parent, anon_idx++);
28574 }
28575 retval = sv2ssim_ReadFieldMaybe(parent, attr.name, attr.value);
28576 if (!retval) {
28577 break;
28578 }
28579 }ind_end;
28580 return retval;
28581}
28582
28583// --- command.sv2ssim..Init
28584// Set all fields to initial values.
28585void command::sv2ssim_Init(command::sv2ssim& parent) {
28586 parent.in = algo::strptr("data");
28587 parent.separator = char(',');
28588 parent.outseparator = algo::strptr("");
28589 parent.header = bool(true);
28590 parent.ctype = algo::strptr("");
28591 parent.ssimfile = algo::strptr("");
28592 parent.schema = bool(false);
28593 Regx_ReadSql(parent.field, "%", true);
28594 parent.data = bool(false);
28595 parent.report = bool(true);
28596 parent.prefer_signed = bool(false);
28597}
28598
28599// --- command.sv2ssim..ToCmdline
28600// Convenience function that returns a full command line
28601// Assume command is in a directory called bin
28602tempstr command::sv2ssim_ToCmdline(command::sv2ssim& row) {
28603 tempstr ret;
28604 ret << "bin/sv2ssim ";
28605 sv2ssim_PrintArgv(row, ret);
28606 // inherit less intense verbose, debug options
28607 for (int i = 1; i < algo_lib::_db.cmdline.verbose; i++) {
28608 ret << " -verbose";
28609 }
28610 for (int i = 1; i < algo_lib::_db.cmdline.debug; i++) {
28611 ret << " -debug";
28612 }
28613 return ret;
28614}
28615
28616// --- command.sv2ssim..PrintArgv
28617// print string representation of ROW to string STR
28618// cfmt:command.sv2ssim.Argv printfmt:Tuple
28619void command::sv2ssim_PrintArgv(command::sv2ssim& row, algo::cstring& str) {
28620 algo::tempstr temp;
28621 (void)temp;
28622 (void)str;
28623 if (!(row.in == "data")) {
28624 ch_RemoveAll(temp);
28625 cstring_Print(row.in, temp);
28626 str << " -in:";
28627 strptr_PrintBash(temp,str);
28628 }
28629 ch_RemoveAll(temp);
28630 cstring_Print(row.fname, temp);
28631 str << " -fname:";
28632 strptr_PrintBash(temp,str);
28633 if (!(row.separator == ',')) {
28634 ch_RemoveAll(temp);
28635 char_Print(row.separator, temp);
28636 str << " -separator:";
28637 strptr_PrintBash(temp,str);
28638 }
28639 if (!(row.outseparator == "")) {
28640 ch_RemoveAll(temp);
28641 cstring_Print(row.outseparator, temp);
28642 str << " -outseparator:";
28643 strptr_PrintBash(temp,str);
28644 }
28645 if (!(row.header == true)) {
28646 ch_RemoveAll(temp);
28647 bool_Print(row.header, temp);
28648 str << " -header:";
28649 strptr_PrintBash(temp,str);
28650 }
28651 if (!(row.ctype == "")) {
28652 ch_RemoveAll(temp);
28653 cstring_Print(row.ctype, temp);
28654 str << " -ctype:";
28655 strptr_PrintBash(temp,str);
28656 }
28657 if (!(row.ssimfile == "")) {
28658 ch_RemoveAll(temp);
28659 cstring_Print(row.ssimfile, temp);
28660 str << " -ssimfile:";
28661 strptr_PrintBash(temp,str);
28662 }
28663 if (!(row.schema == false)) {
28664 ch_RemoveAll(temp);
28665 bool_Print(row.schema, temp);
28666 str << " -schema:";
28667 strptr_PrintBash(temp,str);
28668 }
28669 if (!(row.field.expr == "%")) {
28670 ch_RemoveAll(temp);
28671 command::field_Print(const_cast<command::sv2ssim&>(row), temp);
28672 str << " -field:";
28673 strptr_PrintBash(temp,str);
28674 }
28675 if (!(row.data == false)) {
28676 ch_RemoveAll(temp);
28677 bool_Print(row.data, temp);
28678 str << " -data:";
28679 strptr_PrintBash(temp,str);
28680 }
28681 if (!(row.report == true)) {
28682 ch_RemoveAll(temp);
28683 bool_Print(row.report, temp);
28684 str << " -report:";
28685 strptr_PrintBash(temp,str);
28686 }
28687 if (!(row.prefer_signed == false)) {
28688 ch_RemoveAll(temp);
28689 bool_Print(row.prefer_signed, temp);
28690 str << " -prefer_signed:";
28691 strptr_PrintBash(temp,str);
28692 }
28693}
28694
28695// --- command.sv2ssim..GetAnon
28696algo::strptr command::sv2ssim_GetAnon(command::sv2ssim &parent, i32 idx) {
28697 (void)parent;//only to avoid -Wunused-parameter
28698 switch(idx) {
28699 case(0): return strptr("fname", 5);
28700 default: return algo::strptr();
28701 }
28702}
28703
28704// --- command.sv2ssim..NArgs
28705// Used with command lines
28706// Return # of command-line arguments that must follow this argument
28707// If FIELD is invalid, return -1
28708i32 command::sv2ssim_NArgs(command::FieldId field, algo::strptr& out_dflt, bool* out_anon) {
28709 i32 retval = 1;
28710 switch (field) {
28711 case command_FieldId_in: { // $comment
28712 *out_anon = false;
28713 } break;
28714 case command_FieldId_fname: { // $comment
28715 *out_anon = true;
28716 } break;
28717 case command_FieldId_separator: { // $comment
28718 *out_anon = false;
28719 } break;
28720 case command_FieldId_outseparator: { // $comment
28721 *out_anon = false;
28722 } break;
28723 case command_FieldId_header: { // $comment
28724 *out_anon = false;
28725 retval=0;
28726 out_dflt="Y";
28727 } break;
28728 case command_FieldId_ctype: { // bool: no argument required but value may be specified as header:Y
28729 *out_anon = false;
28730 } break;
28731 case command_FieldId_ssimfile: { // bool: no argument required but value may be specified as header:Y
28732 *out_anon = false;
28733 } break;
28734 case command_FieldId_schema: { // bool: no argument required but value may be specified as header:Y
28735 *out_anon = false;
28736 retval=0;
28737 out_dflt="Y";
28738 } break;
28739 case command_FieldId_field: { // bool: no argument required but value may be specified as schema:Y
28740 *out_anon = false;
28741 } break;
28742 case command_FieldId_data: { // bool: no argument required but value may be specified as schema:Y
28743 *out_anon = false;
28744 retval=0;
28745 out_dflt="Y";
28746 } break;
28747 case command_FieldId_report: { // bool: no argument required but value may be specified as data:Y
28748 *out_anon = false;
28749 retval=0;
28750 out_dflt="Y";
28751 } break;
28752 case command_FieldId_prefer_signed: { // bool: no argument required but value may be specified as report:Y
28753 *out_anon = false;
28754 retval=0;
28755 out_dflt="Y";
28756 } break;
28757 default:
28758 retval=-1; // unrecognized
28759 }
28760 return retval;
28761}
28762
28763// --- command.sv2ssim_proc.sv2ssim.Start
28764// Start subprocess
28765// If subprocess already running, do nothing. Otherwise, start it
28766int command::sv2ssim_Start(command::sv2ssim_proc& parent) {
28767 int retval = 0;
28768 if (parent.pid == 0) {
28769 verblog(sv2ssim_ToCmdline(parent)); // maybe print command
28770#ifdef WIN32
28771 algo_lib::ResolveExecFname(parent.path);
28772 tempstr cmdline(sv2ssim_ToCmdline(parent));
28773 parent.pid = dospawn(Zeroterm(parent.path),Zeroterm(cmdline),parent.timeout,parent.fstdin,parent.fstdout,parent.fstderr);
28774#else
28775 parent.pid = fork();
28776 if (parent.pid == 0) { // child
28777 algo_lib::DieWithParent();
28778 if (parent.timeout > 0) {
28779 alarm(parent.timeout);
28780 }
28781 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstdin , 0);
28782 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstdout, 1);
28783 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstderr, 2);
28784 if (retval==0) retval= sv2ssim_Execv(parent);
28785 if (retval != 0) { // if start fails, print error
28786 int err=errno;
28787 prerr("command.sv2ssim_execv"
28788 <<Keyval("errno",err)
28789 <<Keyval("errstr",strerror(err))
28790 <<Keyval("comment","Execv failed"));
28791 }
28792 _exit(127); // if failed to start, exit anyway
28793 } else if (parent.pid == -1) {
28794 retval = errno; // failed to fork
28795 }
28796#endif
28797 }
28798 parent.status = parent.pid > 0 ? 0 : -1; // if didn't start, set error status
28799 return retval;
28800}
28801
28802// --- command.sv2ssim_proc.sv2ssim.StartRead
28803// Start subprocess & Read output
28804algo::Fildes command::sv2ssim_StartRead(command::sv2ssim_proc& parent, algo_lib::FFildes &read) {
28805 int pipefd[2];
28806 int rc=pipe(pipefd);
28807 (void)rc;
28808 read.fd.value = pipefd[0];
28809 parent.fstdout << ">&" << pipefd[1];
28810 sv2ssim_Start(parent);
28811 (void)close(pipefd[1]);
28812 return read.fd;
28813}
28814
28815// --- command.sv2ssim_proc.sv2ssim.Kill
28816// Kill subprocess and wait
28817void command::sv2ssim_Kill(command::sv2ssim_proc& parent) {
28818 if (parent.pid != 0) {
28819 kill(parent.pid,9);
28820 sv2ssim_Wait(parent);
28821 }
28822}
28823
28824// --- command.sv2ssim_proc.sv2ssim.Wait
28825// Wait for subprocess to return
28826void command::sv2ssim_Wait(command::sv2ssim_proc& parent) {
28827 if (parent.pid > 0) {
28828 int wait_flags = 0;
28829 int wait_status = 0;
28830 int rc = -1;
28831 do {
28832 // really wait for subprocess to exit
28833 rc = waitpid(parent.pid,&wait_status,wait_flags);
28834 } while (rc==-1 && errno==EINTR);
28835 if (rc == parent.pid) {
28836 parent.status = wait_status;
28837 parent.pid = 0;
28838 }
28839 }
28840}
28841
28842// --- command.sv2ssim_proc.sv2ssim.Exec
28843// Start + Wait
28844// Execute subprocess and return exit code
28845int command::sv2ssim_Exec(command::sv2ssim_proc& parent) {
28846 sv2ssim_Start(parent);
28847 sv2ssim_Wait(parent);
28848 return parent.status;
28849}
28850
28851// --- command.sv2ssim_proc.sv2ssim.ExecX
28852// Start + Wait, throw exception on error
28853// Execute subprocess; throw human-readable exception on error
28854void command::sv2ssim_ExecX(command::sv2ssim_proc& parent) {
28855 int rc = sv2ssim_Exec(parent);
28856 vrfy(rc==0, tempstr() << "algo_lib.exec" << Keyval("cmd",sv2ssim_ToCmdline(parent))
28857 << Keyval("comment",algo::DescribeWaitStatus(parent.status)));
28858}
28859
28860// --- command.sv2ssim_proc.sv2ssim.Execv
28861// Call execv()
28862// Call execv with specified parameters
28863int command::sv2ssim_Execv(command::sv2ssim_proc& parent) {
28864 int ret = 0;
28865 algo::StringAry args;
28866 sv2ssim_ToArgv(parent, args);
28867 char **argv = (char**)alloca((ary_N(args)+1)*sizeof(*argv));
28868 ind_beg(algo::StringAry_ary_curs,arg,args) {
28869 argv[ind_curs(arg).index] = Zeroterm(arg);
28870 }ind_end;
28871 argv[ary_N(args)] = NULL;
28872 // if parent.path is relative, search for it in PATH
28873 algo_lib::ResolveExecFname(parent.path);
28874 ret = execv(Zeroterm(parent.path),argv);
28875 return ret;
28876}
28877
28878// --- command.sv2ssim_proc.sv2ssim.ToCmdline
28879algo::tempstr command::sv2ssim_ToCmdline(command::sv2ssim_proc& parent) {
28880 algo::tempstr retval;
28881 retval << parent.path << " ";
28882 command::sv2ssim_PrintArgv(parent.cmd,retval);
28883 if (ch_N(parent.fstdin)) {
28884 retval << " " << parent.fstdin;
28885 }
28886 if (ch_N(parent.fstdout)) {
28887 retval << " " << parent.fstdout;
28888 }
28889 if (ch_N(parent.fstderr)) {
28890 retval << " 2" << parent.fstderr;
28891 }
28892 return retval;
28893}
28894
28895// --- command.sv2ssim_proc.sv2ssim.ToArgv
28896// Form array from the command line
28897void command::sv2ssim_ToArgv(command::sv2ssim_proc& parent, algo::StringAry& args) {
28898 ary_RemoveAll(args);
28899 ary_Alloc(args) << parent.path;
28900
28901 if (parent.cmd.in != "data") {
28902 cstring *arg = &ary_Alloc(args);
28903 *arg << "-in:";
28904 cstring_Print(parent.cmd.in, *arg);
28905 }
28906
28907 if (true) {
28908 cstring *arg = &ary_Alloc(args);
28909 *arg << "-fname:";
28910 cstring_Print(parent.cmd.fname, *arg);
28911 }
28912
28913 if (parent.cmd.separator != ',') {
28914 cstring *arg = &ary_Alloc(args);
28915 *arg << "-separator:";
28916 char_Print(parent.cmd.separator, *arg);
28917 }
28918
28919 if (parent.cmd.outseparator != "") {
28920 cstring *arg = &ary_Alloc(args);
28921 *arg << "-outseparator:";
28922 cstring_Print(parent.cmd.outseparator, *arg);
28923 }
28924
28925 if (parent.cmd.header != true) {
28926 cstring *arg = &ary_Alloc(args);
28927 *arg << "-header:";
28928 bool_Print(parent.cmd.header, *arg);
28929 }
28930
28931 if (parent.cmd.ctype != "") {
28932 cstring *arg = &ary_Alloc(args);
28933 *arg << "-ctype:";
28934 cstring_Print(parent.cmd.ctype, *arg);
28935 }
28936
28937 if (parent.cmd.ssimfile != "") {
28938 cstring *arg = &ary_Alloc(args);
28939 *arg << "-ssimfile:";
28940 cstring_Print(parent.cmd.ssimfile, *arg);
28941 }
28942
28943 if (parent.cmd.schema != false) {
28944 cstring *arg = &ary_Alloc(args);
28945 *arg << "-schema:";
28946 bool_Print(parent.cmd.schema, *arg);
28947 }
28948
28949 if (parent.cmd.field.expr != "%") {
28950 cstring *arg = &ary_Alloc(args);
28951 *arg << "-field:";
28952 command::field_Print(parent.cmd, *arg);
28953 }
28954
28955 if (parent.cmd.data != false) {
28956 cstring *arg = &ary_Alloc(args);
28957 *arg << "-data:";
28958 bool_Print(parent.cmd.data, *arg);
28959 }
28960
28961 if (parent.cmd.report != true) {
28962 cstring *arg = &ary_Alloc(args);
28963 *arg << "-report:";
28964 bool_Print(parent.cmd.report, *arg);
28965 }
28966
28967 if (parent.cmd.prefer_signed != false) {
28968 cstring *arg = &ary_Alloc(args);
28969 *arg << "-prefer_signed:";
28970 bool_Print(parent.cmd.prefer_signed, *arg);
28971 }
28972 for (int i=1; i < algo_lib::_db.cmdline.verbose; ++i) {
28973 ary_Alloc(args) << "-verbose";
28974 }
28975}
28976
28977// --- command.sv2ssim_proc..Uninit
28978void command::sv2ssim_proc_Uninit(command::sv2ssim_proc& parent) {
28979 command::sv2ssim_proc &row = parent; (void)row;
28980
28981 // command.sv2ssim_proc.sv2ssim.Uninit (Exec) //
28982 sv2ssim_Kill(parent); // kill child, ensure forward progress
28983}
28984
28985// --- command.ttrack..ReadFieldMaybe
28986bool command::ttrack_ReadFieldMaybe(command::ttrack& parent, algo::strptr field, algo::strptr strval) {
28987 bool retval = true;
28988 command::FieldId field_id;
28989 (void)value_SetStrptrMaybe(field_id,field);
28990 switch(field_id) {
28991 case command_FieldId_in: {
28992 retval = algo::cstring_ReadStrptrMaybe(parent.in, strval);
28993 break;
28994 }
28995 case command_FieldId_begin: {
28996 retval = bool_ReadStrptrMaybe(parent.begin, strval);
28997 break;
28998 }
28999 case command_FieldId_end: {
29000 retval = bool_ReadStrptrMaybe(parent.end, strval);
29001 break;
29002 }
29003 case command_FieldId_stay: {
29004 retval = bool_ReadStrptrMaybe(parent.stay, strval);
29005 break;
29006 }
29007 case command_FieldId_logfile: {
29008 retval = algo::cstring_ReadStrptrMaybe(parent.logfile, strval);
29009 break;
29010 }
29011 case command_FieldId_report: {
29012 retval = bool_ReadStrptrMaybe(parent.report, strval);
29013 break;
29014 }
29015 case command_FieldId_from: {
29016 retval = algo::UnTime_ReadStrptrMaybe(parent.from, strval);
29017 break;
29018 }
29019 case command_FieldId_to: {
29020 retval = algo::UnTime_ReadStrptrMaybe(parent.to, strval);
29021 break;
29022 }
29023 case command_FieldId_e: {
29024 retval = bool_ReadStrptrMaybe(parent.e, strval);
29025 break;
29026 }
29027 case command_FieldId_comment: {
29028 retval = algo::cstring_ReadStrptrMaybe(parent.comment, strval);
29029 break;
29030 }
29031 default: break;
29032 }
29033 if (!retval) {
29034 algo_lib::AppendErrtext("attr",field);
29035 }
29036 return retval;
29037}
29038
29039// --- command.ttrack..ReadTupleMaybe
29040// Read fields of command::ttrack from attributes of ascii tuple TUPLE
29041bool command::ttrack_ReadTupleMaybe(command::ttrack &parent, algo::Tuple &tuple) {
29042 bool retval = true;
29043 ind_beg(algo::Tuple_attrs_curs,attr,tuple) {
29044 retval = ttrack_ReadFieldMaybe(parent, attr.name, attr.value);
29045 if (!retval) {
29046 break;
29047 }
29048 }ind_end;
29049 return retval;
29050}
29051
29052// --- command.ttrack..Init
29053// Set all fields to initial values.
29054void command::ttrack_Init(command::ttrack& parent) {
29055 parent.in = algo::strptr("data");
29056 parent.begin = bool(false);
29057 parent.end = bool(false);
29058 parent.stay = bool(false);
29059 parent.logfile = algo::strptr("~/.ssim/ttrack.ssim");
29060 parent.report = bool(true);
29061 parent.e = bool(false);
29062 parent.comment = algo::strptr("");
29063}
29064
29065// --- command.ttrack..ToCmdline
29066// Convenience function that returns a full command line
29067// Assume command is in a directory called bin
29068tempstr command::ttrack_ToCmdline(command::ttrack& row) {
29069 tempstr ret;
29070 ret << "bin/ttrack ";
29071 ttrack_PrintArgv(row, ret);
29072 // inherit less intense verbose, debug options
29073 for (int i = 1; i < algo_lib::_db.cmdline.verbose; i++) {
29074 ret << " -verbose";
29075 }
29076 for (int i = 1; i < algo_lib::_db.cmdline.debug; i++) {
29077 ret << " -debug";
29078 }
29079 return ret;
29080}
29081
29082// --- command.ttrack..PrintArgv
29083// print string representation of ROW to string STR
29084// cfmt:command.ttrack.Argv printfmt:Tuple
29085void command::ttrack_PrintArgv(command::ttrack& row, algo::cstring& str) {
29086 algo::tempstr temp;
29087 (void)temp;
29088 (void)str;
29089 if (!(row.in == "data")) {
29090 ch_RemoveAll(temp);
29091 cstring_Print(row.in, temp);
29092 str << " -in:";
29093 strptr_PrintBash(temp,str);
29094 }
29095 if (!(row.begin == false)) {
29096 ch_RemoveAll(temp);
29097 bool_Print(row.begin, temp);
29098 str << " -begin:";
29099 strptr_PrintBash(temp,str);
29100 }
29101 if (!(row.end == false)) {
29102 ch_RemoveAll(temp);
29103 bool_Print(row.end, temp);
29104 str << " -end:";
29105 strptr_PrintBash(temp,str);
29106 }
29107 if (!(row.stay == false)) {
29108 ch_RemoveAll(temp);
29109 bool_Print(row.stay, temp);
29110 str << " -stay:";
29111 strptr_PrintBash(temp,str);
29112 }
29113 if (!(row.logfile == "~/.ssim/ttrack.ssim")) {
29114 ch_RemoveAll(temp);
29115 cstring_Print(row.logfile, temp);
29116 str << " -logfile:";
29117 strptr_PrintBash(temp,str);
29118 }
29119 if (!(row.report == true)) {
29120 ch_RemoveAll(temp);
29121 bool_Print(row.report, temp);
29122 str << " -report:";
29123 strptr_PrintBash(temp,str);
29124 }
29125 if (!(UnTime_Eq(row.from, algo::UnTime()))) {
29126 ch_RemoveAll(temp);
29127 UnTime_Print(row.from, temp);
29128 str << " -from:";
29129 strptr_PrintBash(temp,str);
29130 }
29131 if (!(UnTime_Eq(row.to, algo::UnTime()))) {
29132 ch_RemoveAll(temp);
29133 UnTime_Print(row.to, temp);
29134 str << " -to:";
29135 strptr_PrintBash(temp,str);
29136 }
29137 if (!(row.e == false)) {
29138 ch_RemoveAll(temp);
29139 bool_Print(row.e, temp);
29140 str << " -e:";
29141 strptr_PrintBash(temp,str);
29142 }
29143 if (!(row.comment == "")) {
29144 ch_RemoveAll(temp);
29145 cstring_Print(row.comment, temp);
29146 str << " -comment:";
29147 strptr_PrintBash(temp,str);
29148 }
29149}
29150
29151// --- command.ttrack..NArgs
29152// Used with command lines
29153// Return # of command-line arguments that must follow this argument
29154// If FIELD is invalid, return -1
29155i32 command::ttrack_NArgs(command::FieldId field, algo::strptr& out_dflt, bool* out_anon) {
29156 i32 retval = 1;
29157 switch (field) {
29158 case command_FieldId_in: { // $comment
29159 *out_anon = false;
29160 } break;
29161 case command_FieldId_begin: { // $comment
29162 *out_anon = false;
29163 retval=0;
29164 out_dflt="Y";
29165 } break;
29166 case command_FieldId_end: { // bool: no argument required but value may be specified as begin:Y
29167 *out_anon = false;
29168 retval=0;
29169 out_dflt="Y";
29170 } break;
29171 case command_FieldId_stay: { // bool: no argument required but value may be specified as end:Y
29172 *out_anon = false;
29173 retval=0;
29174 out_dflt="Y";
29175 } break;
29176 case command_FieldId_logfile: { // bool: no argument required but value may be specified as stay:Y
29177 *out_anon = false;
29178 } break;
29179 case command_FieldId_report: { // bool: no argument required but value may be specified as stay:Y
29180 *out_anon = false;
29181 retval=0;
29182 out_dflt="Y";
29183 } break;
29184 case command_FieldId_from: { // bool: no argument required but value may be specified as report:Y
29185 *out_anon = false;
29186 } break;
29187 case command_FieldId_to: { // bool: no argument required but value may be specified as report:Y
29188 *out_anon = false;
29189 } break;
29190 case command_FieldId_e: { // bool: no argument required but value may be specified as report:Y
29191 *out_anon = false;
29192 retval=0;
29193 out_dflt="Y";
29194 } break;
29195 case command_FieldId_comment: { // bool: no argument required but value may be specified as e:Y
29196 *out_anon = false;
29197 } break;
29198 default:
29199 retval=-1; // unrecognized
29200 }
29201 return retval;
29202}
29203
29204// --- command.ttrack_proc.ttrack.Start
29205// Start subprocess
29206// If subprocess already running, do nothing. Otherwise, start it
29207int command::ttrack_Start(command::ttrack_proc& parent) {
29208 int retval = 0;
29209 if (parent.pid == 0) {
29210 verblog(ttrack_ToCmdline(parent)); // maybe print command
29211#ifdef WIN32
29212 algo_lib::ResolveExecFname(parent.path);
29213 tempstr cmdline(ttrack_ToCmdline(parent));
29214 parent.pid = dospawn(Zeroterm(parent.path),Zeroterm(cmdline),parent.timeout,parent.fstdin,parent.fstdout,parent.fstderr);
29215#else
29216 parent.pid = fork();
29217 if (parent.pid == 0) { // child
29218 algo_lib::DieWithParent();
29219 if (parent.timeout > 0) {
29220 alarm(parent.timeout);
29221 }
29222 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstdin , 0);
29223 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstdout, 1);
29224 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstderr, 2);
29225 if (retval==0) retval= ttrack_Execv(parent);
29226 if (retval != 0) { // if start fails, print error
29227 int err=errno;
29228 prerr("command.ttrack_execv"
29229 <<Keyval("errno",err)
29230 <<Keyval("errstr",strerror(err))
29231 <<Keyval("comment","Execv failed"));
29232 }
29233 _exit(127); // if failed to start, exit anyway
29234 } else if (parent.pid == -1) {
29235 retval = errno; // failed to fork
29236 }
29237#endif
29238 }
29239 parent.status = parent.pid > 0 ? 0 : -1; // if didn't start, set error status
29240 return retval;
29241}
29242
29243// --- command.ttrack_proc.ttrack.StartRead
29244// Start subprocess & Read output
29245algo::Fildes command::ttrack_StartRead(command::ttrack_proc& parent, algo_lib::FFildes &read) {
29246 int pipefd[2];
29247 int rc=pipe(pipefd);
29248 (void)rc;
29249 read.fd.value = pipefd[0];
29250 parent.fstdout << ">&" << pipefd[1];
29251 ttrack_Start(parent);
29252 (void)close(pipefd[1]);
29253 return read.fd;
29254}
29255
29256// --- command.ttrack_proc.ttrack.Kill
29257// Kill subprocess and wait
29258void command::ttrack_Kill(command::ttrack_proc& parent) {
29259 if (parent.pid != 0) {
29260 kill(parent.pid,9);
29261 ttrack_Wait(parent);
29262 }
29263}
29264
29265// --- command.ttrack_proc.ttrack.Wait
29266// Wait for subprocess to return
29267void command::ttrack_Wait(command::ttrack_proc& parent) {
29268 if (parent.pid > 0) {
29269 int wait_flags = 0;
29270 int wait_status = 0;
29271 int rc = -1;
29272 do {
29273 // really wait for subprocess to exit
29274 rc = waitpid(parent.pid,&wait_status,wait_flags);
29275 } while (rc==-1 && errno==EINTR);
29276 if (rc == parent.pid) {
29277 parent.status = wait_status;
29278 parent.pid = 0;
29279 }
29280 }
29281}
29282
29283// --- command.ttrack_proc.ttrack.Exec
29284// Start + Wait
29285// Execute subprocess and return exit code
29286int command::ttrack_Exec(command::ttrack_proc& parent) {
29287 ttrack_Start(parent);
29288 ttrack_Wait(parent);
29289 return parent.status;
29290}
29291
29292// --- command.ttrack_proc.ttrack.ExecX
29293// Start + Wait, throw exception on error
29294// Execute subprocess; throw human-readable exception on error
29295void command::ttrack_ExecX(command::ttrack_proc& parent) {
29296 int rc = ttrack_Exec(parent);
29297 vrfy(rc==0, tempstr() << "algo_lib.exec" << Keyval("cmd",ttrack_ToCmdline(parent))
29298 << Keyval("comment",algo::DescribeWaitStatus(parent.status)));
29299}
29300
29301// --- command.ttrack_proc.ttrack.Execv
29302// Call execv()
29303// Call execv with specified parameters
29304int command::ttrack_Execv(command::ttrack_proc& parent) {
29305 int ret = 0;
29306 algo::StringAry args;
29307 ttrack_ToArgv(parent, args);
29308 char **argv = (char**)alloca((ary_N(args)+1)*sizeof(*argv));
29309 ind_beg(algo::StringAry_ary_curs,arg,args) {
29310 argv[ind_curs(arg).index] = Zeroterm(arg);
29311 }ind_end;
29312 argv[ary_N(args)] = NULL;
29313 // if parent.path is relative, search for it in PATH
29314 algo_lib::ResolveExecFname(parent.path);
29315 ret = execv(Zeroterm(parent.path),argv);
29316 return ret;
29317}
29318
29319// --- command.ttrack_proc.ttrack.ToCmdline
29320algo::tempstr command::ttrack_ToCmdline(command::ttrack_proc& parent) {
29321 algo::tempstr retval;
29322 retval << parent.path << " ";
29323 command::ttrack_PrintArgv(parent.cmd,retval);
29324 if (ch_N(parent.fstdin)) {
29325 retval << " " << parent.fstdin;
29326 }
29327 if (ch_N(parent.fstdout)) {
29328 retval << " " << parent.fstdout;
29329 }
29330 if (ch_N(parent.fstderr)) {
29331 retval << " 2" << parent.fstderr;
29332 }
29333 return retval;
29334}
29335
29336// --- command.ttrack_proc.ttrack.ToArgv
29337// Form array from the command line
29338void command::ttrack_ToArgv(command::ttrack_proc& parent, algo::StringAry& args) {
29339 ary_RemoveAll(args);
29340 ary_Alloc(args) << parent.path;
29341
29342 if (parent.cmd.in != "data") {
29343 cstring *arg = &ary_Alloc(args);
29344 *arg << "-in:";
29345 cstring_Print(parent.cmd.in, *arg);
29346 }
29347
29348 if (parent.cmd.begin != false) {
29349 cstring *arg = &ary_Alloc(args);
29350 *arg << "-begin:";
29351 bool_Print(parent.cmd.begin, *arg);
29352 }
29353
29354 if (parent.cmd.end != false) {
29355 cstring *arg = &ary_Alloc(args);
29356 *arg << "-end:";
29357 bool_Print(parent.cmd.end, *arg);
29358 }
29359
29360 if (parent.cmd.stay != false) {
29361 cstring *arg = &ary_Alloc(args);
29362 *arg << "-stay:";
29363 bool_Print(parent.cmd.stay, *arg);
29364 }
29365
29366 if (parent.cmd.logfile != "~/.ssim/ttrack.ssim") {
29367 cstring *arg = &ary_Alloc(args);
29368 *arg << "-logfile:";
29369 cstring_Print(parent.cmd.logfile, *arg);
29370 }
29371
29372 if (parent.cmd.report != true) {
29373 cstring *arg = &ary_Alloc(args);
29374 *arg << "-report:";
29375 bool_Print(parent.cmd.report, *arg);
29376 }
29377
29378 if (true) {
29379 cstring *arg = &ary_Alloc(args);
29380 *arg << "-from:";
29381 UnTime_Print(parent.cmd.from, *arg);
29382 }
29383
29384 if (true) {
29385 cstring *arg = &ary_Alloc(args);
29386 *arg << "-to:";
29387 UnTime_Print(parent.cmd.to, *arg);
29388 }
29389
29390 if (parent.cmd.e != false) {
29391 cstring *arg = &ary_Alloc(args);
29392 *arg << "-e:";
29393 bool_Print(parent.cmd.e, *arg);
29394 }
29395
29396 if (parent.cmd.comment != "") {
29397 cstring *arg = &ary_Alloc(args);
29398 *arg << "-comment:";
29399 cstring_Print(parent.cmd.comment, *arg);
29400 }
29401 for (int i=1; i < algo_lib::_db.cmdline.verbose; ++i) {
29402 ary_Alloc(args) << "-verbose";
29403 }
29404}
29405
29406// --- command.ttrack_proc..Uninit
29407void command::ttrack_proc_Uninit(command::ttrack_proc& parent) {
29408 command::ttrack_proc &row = parent; (void)row;
29409
29410 // command.ttrack_proc.ttrack.Uninit (Exec) //
29411 ttrack_Kill(parent); // kill child, ensure forward progress
29412}
29413
29414// --- command.wcli.fields.Addary
29415// Reserve space (this may move memory). Insert N element at the end.
29416// Return aryptr to newly inserted block.
29417// If the RHS argument aliases the array (refers to the same memory), exit program with fatal error.
29418algo::aryptr<algo::cstring> command::fields_Addary(command::wcli& parent, algo::aryptr<algo::cstring> rhs) {
29419 bool overlaps = rhs.n_elems>0 && rhs.elems >= parent.fields_elems && rhs.elems < parent.fields_elems + parent.fields_max;
29420 if (UNLIKELY(overlaps)) {
29421 FatalErrorExit("command.tary_alias field:command.wcli.fields comment:'alias error: sub-array is being appended to the whole'");
29422 }
29423 int nnew = rhs.n_elems;
29424 fields_Reserve(parent, nnew); // reserve space
29425 int at = parent.fields_n;
29426 for (int i = 0; i < nnew; i++) {
29427 new (parent.fields_elems + at + i) algo::cstring(rhs[i]);
29428 parent.fields_n++;
29429 }
29430 return algo::aryptr<algo::cstring>(parent.fields_elems + at, nnew);
29431}
29432
29433// --- command.wcli.fields.Alloc
29434// Reserve space. Insert element at the end
29435// The new element is initialized to a default value
29436algo::cstring& command::fields_Alloc(command::wcli& parent) {
29437 fields_Reserve(parent, 1);
29438 int n = parent.fields_n;
29439 int at = n;
29440 algo::cstring *elems = parent.fields_elems;
29441 new (elems + at) algo::cstring(""); // construct new element, default initializer
29442 parent.fields_n = n+1;
29443 return elems[at];
29444}
29445
29446// --- command.wcli.fields.AllocAt
29447// Reserve space for new element, reallocating the array if necessary
29448// Insert new element at specified index. Index must be in range or a fatal error occurs.
29449algo::cstring& command::fields_AllocAt(command::wcli& parent, int at) {
29450 fields_Reserve(parent, 1);
29451 int n = parent.fields_n;
29452 if (UNLIKELY(u64(at) >= u64(n+1))) {
29453 FatalErrorExit("command.bad_alloc_at field:command.wcli.fields comment:'index out of range'");
29454 }
29455 algo::cstring *elems = parent.fields_elems;
29456 memmove(elems + at + 1, elems + at, (n - at) * sizeof(algo::cstring));
29457 new (elems + at) algo::cstring(""); // construct element, default initializer
29458 parent.fields_n = n+1;
29459 return elems[at];
29460}
29461
29462// --- command.wcli.fields.AllocN
29463// Reserve space. Insert N elements at the end of the array, return pointer to array
29464algo::aryptr<algo::cstring> command::fields_AllocN(command::wcli& parent, int n_elems) {
29465 fields_Reserve(parent, n_elems);
29466 int old_n = parent.fields_n;
29467 int new_n = old_n + n_elems;
29468 algo::cstring *elems = parent.fields_elems;
29469 for (int i = old_n; i < new_n; i++) {
29470 new (elems + i) algo::cstring(""); // construct new element, default initialize
29471 }
29472 parent.fields_n = new_n;
29473 return algo::aryptr<algo::cstring>(elems + old_n, n_elems);
29474}
29475
29476// --- command.wcli.fields.Remove
29477// Remove item by index. If index outside of range, do nothing.
29478void command::fields_Remove(command::wcli& parent, u32 i) {
29479 u32 lim = parent.fields_n;
29480 algo::cstring *elems = parent.fields_elems;
29481 if (i < lim) {
29482 elems[i].~cstring(); // destroy element
29483 memmove(elems + i, elems + (i + 1), sizeof(algo::cstring) * (lim - (i + 1)));
29484 parent.fields_n = lim - 1;
29485 }
29486}
29487
29488// --- command.wcli.fields.RemoveAll
29489void command::fields_RemoveAll(command::wcli& parent) {
29490 u32 n = parent.fields_n;
29491 while (n > 0) {
29492 n -= 1;
29493 parent.fields_elems[n].~cstring();
29494 parent.fields_n = n;
29495 }
29496}
29497
29498// --- command.wcli.fields.RemoveLast
29499// Delete last element of array. Do nothing if array is empty.
29500void command::fields_RemoveLast(command::wcli& parent) {
29501 u64 n = parent.fields_n;
29502 if (n > 0) {
29503 n -= 1;
29504 fields_qFind(parent, u64(n)).~cstring();
29505 parent.fields_n = n;
29506 }
29507}
29508
29509// --- command.wcli.fields.AbsReserve
29510// Make sure N elements fit in array. Process dies if out of memory
29511void command::fields_AbsReserve(command::wcli& parent, int n) {
29512 u32 old_max = parent.fields_max;
29513 if (n > i32(old_max)) {
29514 u32 new_max = i32_Max(i32_Max(old_max * 2, n), 4);
29515 void *new_mem = algo_lib::malloc_ReallocMem(parent.fields_elems, old_max * sizeof(algo::cstring), new_max * sizeof(algo::cstring));
29516 if (UNLIKELY(!new_mem)) {
29517 FatalErrorExit("command.tary_nomem field:command.wcli.fields comment:'out of memory'");
29518 }
29519 parent.fields_elems = (algo::cstring*)new_mem;
29520 parent.fields_max = new_max;
29521 }
29522}
29523
29524// --- command.wcli.fields.Setary
29525// Copy contents of RHS to PARENT.
29526void command::fields_Setary(command::wcli& parent, command::wcli &rhs) {
29527 fields_RemoveAll(parent);
29528 int nnew = rhs.fields_n;
29529 fields_Reserve(parent, nnew); // reserve space
29530 for (int i = 0; i < nnew; i++) { // copy elements over
29531 new (parent.fields_elems + i) algo::cstring(fields_qFind(rhs, i));
29532 parent.fields_n = i + 1;
29533 }
29534}
29535
29536// --- command.wcli.fields.Setary2
29537// Copy specified array into fields, discarding previous contents.
29538// If the RHS argument aliases the array (refers to the same memory), throw exception.
29539void command::fields_Setary(command::wcli& parent, const algo::aryptr<algo::cstring> &rhs) {
29540 fields_RemoveAll(parent);
29541 fields_Addary(parent, rhs);
29542}
29543
29544// --- command.wcli.fields.AllocNVal
29545// Reserve space. Insert N elements at the end of the array, return pointer to array
29546algo::aryptr<algo::cstring> command::fields_AllocNVal(command::wcli& parent, int n_elems, const algo::cstring& val) {
29547 fields_Reserve(parent, n_elems);
29548 int old_n = parent.fields_n;
29549 int new_n = old_n + n_elems;
29550 algo::cstring *elems = parent.fields_elems;
29551 for (int i = old_n; i < new_n; i++) {
29552 new (elems + i) algo::cstring(val);
29553 }
29554 parent.fields_n = new_n;
29555 return algo::aryptr<algo::cstring>(elems + old_n, n_elems);
29556}
29557
29558// --- command.wcli.fields.ReadStrptrMaybe
29559// A single element is read from input string and appended to the array.
29560// If the string contains an error, the array is untouched.
29561// Function returns success value.
29562bool command::fields_ReadStrptrMaybe(command::wcli& parent, algo::strptr in_str) {
29563 bool retval = true;
29564 algo::cstring &elem = fields_Alloc(parent);
29565 retval = algo::cstring_ReadStrptrMaybe(elem, in_str);
29566 if (!retval) {
29567 fields_RemoveLast(parent);
29568 }
29569 return retval;
29570}
29571
29572// --- command.wcli..ReadFieldMaybe
29573bool command::wcli_ReadFieldMaybe(command::wcli& parent, algo::strptr field, algo::strptr strval) {
29574 bool retval = true;
29575 command::FieldId field_id;
29576 (void)value_SetStrptrMaybe(field_id,algo::Pathcomp(field, ".LL"));
29577 switch(field_id) {
29578 case command_FieldId_selector: {
29579 retval = algo::Smallstr50_ReadStrptrMaybe(parent.selector, strval);
29580 break;
29581 }
29582 case command_FieldId_fields: {
29583 retval = fields_ReadStrptrMaybe(parent, strval);
29584 break;
29585 }
29586 case command_FieldId_list: {
29587 retval = bool_ReadStrptrMaybe(parent.list, strval);
29588 break;
29589 }
29590 case command_FieldId_create: {
29591 retval = bool_ReadStrptrMaybe(parent.create, strval);
29592 break;
29593 }
29594 case command_FieldId_update: {
29595 retval = bool_ReadStrptrMaybe(parent.update, strval);
29596 break;
29597 }
29598 case command_FieldId_download: {
29599 retval = bool_ReadStrptrMaybe(parent.download, strval);
29600 break;
29601 }
29602 case command_FieldId_upload: {
29603 retval = bool_ReadStrptrMaybe(parent.upload, strval);
29604 break;
29605 }
29606 case command_FieldId_remove: {
29607 retval = bool_ReadStrptrMaybe(parent.remove, strval);
29608 break;
29609 }
29610 case command_FieldId_t: {
29611 retval = bool_ReadStrptrMaybe(parent.t, strval);
29612 break;
29613 }
29614 case command_FieldId_e: {
29615 retval = bool_ReadStrptrMaybe(parent.e, strval);
29616 break;
29617 }
29618 case command_FieldId_ignore_saved_edit: {
29619 retval = bool_ReadStrptrMaybe(parent.ignore_saved_edit, strval);
29620 break;
29621 }
29622 case command_FieldId_exclude_subpages: {
29623 retval = bool_ReadStrptrMaybe(parent.exclude_subpages, strval);
29624 break;
29625 }
29626 case command_FieldId_authdir: {
29627 retval = algo::cstring_ReadStrptrMaybe(parent.authdir, strval);
29628 break;
29629 }
29630 case command_FieldId_pagedir: {
29631 retval = algo::cstring_ReadStrptrMaybe(parent.pagedir, strval);
29632 break;
29633 }
29634 case command_FieldId_in: {
29635 retval = algo::cstring_ReadStrptrMaybe(parent.in, strval);
29636 break;
29637 }
29638 case command_FieldId_dry_run: {
29639 retval = bool_ReadStrptrMaybe(parent.dry_run, strval);
29640 break;
29641 }
29642 default: break;
29643 }
29644 if (!retval) {
29645 algo_lib::AppendErrtext("attr",field);
29646 }
29647 return retval;
29648}
29649
29650// --- command.wcli..ReadTupleMaybe
29651// Read fields of command::wcli from attributes of ascii tuple TUPLE
29652bool command::wcli_ReadTupleMaybe(command::wcli &parent, algo::Tuple &tuple) {
29653 bool retval = true;
29654 int anon_idx = 0;
29655 ind_beg(algo::Tuple_attrs_curs,attr,tuple) {
29656 if (ch_N(attr.name) == 0) {
29657 attr.name = wcli_GetAnon(parent, anon_idx++);
29658 }
29659 retval = wcli_ReadFieldMaybe(parent, attr.name, attr.value);
29660 if (!retval) {
29661 break;
29662 }
29663 }ind_end;
29664 return retval;
29665}
29666
29667// --- command.wcli..Init
29668// Set all fields to initial values.
29669void command::wcli_Init(command::wcli& parent) {
29670 parent.selector = algo::strptr("issue:%");
29671 parent.fields_elems = 0; // (command.wcli.fields)
29672 parent.fields_n = 0; // (command.wcli.fields)
29673 parent.fields_max = 0; // (command.wcli.fields)
29674 parent.list = bool(false);
29675 parent.create = bool(false);
29676 parent.update = bool(false);
29677 parent.download = bool(false);
29678 parent.upload = bool(false);
29679 parent.remove = bool(false);
29680 parent.t = bool(false);
29681 parent.e = bool(false);
29682 parent.ignore_saved_edit = bool(false);
29683 parent.exclude_subpages = bool(false);
29684 parent.authdir = algo::strptr(".ssim");
29685 parent.pagedir = algo::strptr("temp/wcli/download");
29686 parent.in = algo::strptr("data");
29687 parent.dry_run = bool(false);
29688}
29689
29690// --- command.wcli..Uninit
29691void command::wcli_Uninit(command::wcli& parent) {
29692 command::wcli &row = parent; (void)row;
29693
29694 // command.wcli.fields.Uninit (Tary) //additional key:value pairs for use with -create, -list, -update
29695 // remove all elements from command.wcli.fields
29696 fields_RemoveAll(parent);
29697 // free memory for Tary command.wcli.fields
29698 algo_lib::malloc_FreeMem(parent.fields_elems, sizeof(algo::cstring)*parent.fields_max); // (command.wcli.fields)
29699}
29700
29701// --- command.wcli..ToCmdline
29702// Convenience function that returns a full command line
29703// Assume command is in a directory called bin
29704tempstr command::wcli_ToCmdline(command::wcli& row) {
29705 tempstr ret;
29706 ret << "bin/wcli ";
29707 wcli_PrintArgv(row, ret);
29708 // inherit less intense verbose, debug options
29709 for (int i = 1; i < algo_lib::_db.cmdline.verbose; i++) {
29710 ret << " -verbose";
29711 }
29712 for (int i = 1; i < algo_lib::_db.cmdline.debug; i++) {
29713 ret << " -debug";
29714 }
29715 return ret;
29716}
29717
29718// --- command.wcli..PrintArgv
29719// print string representation of ROW to string STR
29720// cfmt:command.wcli.Argv printfmt:Tuple
29721void command::wcli_PrintArgv(command::wcli& row, algo::cstring& str) {
29722 algo::tempstr temp;
29723 (void)temp;
29724 (void)str;
29725 ch_RemoveAll(temp);
29726 Smallstr50_Print(row.selector, temp);
29727 str << " -selector:";
29728 strptr_PrintBash(temp,str);
29729 ind_beg(wcli_fields_curs,value,row) {
29730 ch_RemoveAll(temp);
29731 cstring_Print(value, temp);
29732 str << " -fields:";
29733 strptr_PrintBash(temp,str);
29734 }ind_end;
29735 if (!(row.list == false)) {
29736 ch_RemoveAll(temp);
29737 bool_Print(row.list, temp);
29738 str << " -list:";
29739 strptr_PrintBash(temp,str);
29740 }
29741 if (!(row.create == false)) {
29742 ch_RemoveAll(temp);
29743 bool_Print(row.create, temp);
29744 str << " -create:";
29745 strptr_PrintBash(temp,str);
29746 }
29747 if (!(row.update == false)) {
29748 ch_RemoveAll(temp);
29749 bool_Print(row.update, temp);
29750 str << " -update:";
29751 strptr_PrintBash(temp,str);
29752 }
29753 if (!(row.download == false)) {
29754 ch_RemoveAll(temp);
29755 bool_Print(row.download, temp);
29756 str << " -download:";
29757 strptr_PrintBash(temp,str);
29758 }
29759 if (!(row.upload == false)) {
29760 ch_RemoveAll(temp);
29761 bool_Print(row.upload, temp);
29762 str << " -upload:";
29763 strptr_PrintBash(temp,str);
29764 }
29765 if (!(row.remove == false)) {
29766 ch_RemoveAll(temp);
29767 bool_Print(row.remove, temp);
29768 str << " -remove:";
29769 strptr_PrintBash(temp,str);
29770 }
29771 if (!(row.t == false)) {
29772 ch_RemoveAll(temp);
29773 bool_Print(row.t, temp);
29774 str << " -t:";
29775 strptr_PrintBash(temp,str);
29776 }
29777 if (!(row.e == false)) {
29778 ch_RemoveAll(temp);
29779 bool_Print(row.e, temp);
29780 str << " -e:";
29781 strptr_PrintBash(temp,str);
29782 }
29783 if (!(row.ignore_saved_edit == false)) {
29784 ch_RemoveAll(temp);
29785 bool_Print(row.ignore_saved_edit, temp);
29786 str << " -ignore_saved_edit:";
29787 strptr_PrintBash(temp,str);
29788 }
29789 if (!(row.exclude_subpages == false)) {
29790 ch_RemoveAll(temp);
29791 bool_Print(row.exclude_subpages, temp);
29792 str << " -exclude_subpages:";
29793 strptr_PrintBash(temp,str);
29794 }
29795 if (!(row.authdir == ".ssim")) {
29796 ch_RemoveAll(temp);
29797 cstring_Print(row.authdir, temp);
29798 str << " -authdir:";
29799 strptr_PrintBash(temp,str);
29800 }
29801 if (!(row.pagedir == "temp/wcli/download")) {
29802 ch_RemoveAll(temp);
29803 cstring_Print(row.pagedir, temp);
29804 str << " -pagedir:";
29805 strptr_PrintBash(temp,str);
29806 }
29807 if (!(row.in == "data")) {
29808 ch_RemoveAll(temp);
29809 cstring_Print(row.in, temp);
29810 str << " -in:";
29811 strptr_PrintBash(temp,str);
29812 }
29813 if (!(row.dry_run == false)) {
29814 ch_RemoveAll(temp);
29815 bool_Print(row.dry_run, temp);
29816 str << " -dry_run:";
29817 strptr_PrintBash(temp,str);
29818 }
29819}
29820
29821// --- command.wcli..GetAnon
29822algo::strptr command::wcli_GetAnon(command::wcli &parent, i32 idx) {
29823 (void)parent;//only to avoid -Wunused-parameter
29824 switch(idx) {
29825 case(0): return strptr("selector", 8);
29826 default: return strptr("fields", 6);
29827 }
29828}
29829
29830// --- command.wcli..NArgs
29831// Used with command lines
29832// Return # of command-line arguments that must follow this argument
29833// If FIELD is invalid, return -1
29834i32 command::wcli_NArgs(command::FieldId field, algo::strptr& out_dflt, bool* out_anon) {
29835 i32 retval = 1;
29836 switch (field) {
29837 case command_FieldId_selector: { // $comment
29838 *out_anon = true;
29839 } break;
29840 case command_FieldId_fields: { // $comment
29841 *out_anon = true;
29842 } break;
29843 case command_FieldId_list: { // $comment
29844 *out_anon = false;
29845 retval=0;
29846 out_dflt="Y";
29847 } break;
29848 case command_FieldId_create: { // bool: no argument required but value may be specified as list:Y
29849 *out_anon = false;
29850 retval=0;
29851 out_dflt="Y";
29852 } break;
29853 case command_FieldId_update: { // bool: no argument required but value may be specified as create:Y
29854 *out_anon = false;
29855 retval=0;
29856 out_dflt="Y";
29857 } break;
29858 case command_FieldId_download: { // bool: no argument required but value may be specified as update:Y
29859 *out_anon = false;
29860 retval=0;
29861 out_dflt="Y";
29862 } break;
29863 case command_FieldId_upload: { // bool: no argument required but value may be specified as download:Y
29864 *out_anon = false;
29865 retval=0;
29866 out_dflt="Y";
29867 } break;
29868 case command_FieldId_remove: { // bool: no argument required but value may be specified as upload:Y
29869 *out_anon = false;
29870 retval=0;
29871 out_dflt="Y";
29872 } break;
29873 case command_FieldId_t: { // bool: no argument required but value may be specified as remove:Y
29874 *out_anon = false;
29875 retval=0;
29876 out_dflt="Y";
29877 } break;
29878 case command_FieldId_e: { // bool: no argument required but value may be specified as t:Y
29879 *out_anon = false;
29880 retval=0;
29881 out_dflt="Y";
29882 } break;
29883 case command_FieldId_ignore_saved_edit: { // bool: no argument required but value may be specified as e:Y
29884 *out_anon = false;
29885 retval=0;
29886 out_dflt="Y";
29887 } break;
29888 case command_FieldId_exclude_subpages: { // bool: no argument required but value may be specified as ignore_saved_edit:Y
29889 *out_anon = false;
29890 retval=0;
29891 out_dflt="Y";
29892 } break;
29893 case command_FieldId_authdir: { // bool: no argument required but value may be specified as exclude_subpages:Y
29894 *out_anon = false;
29895 } break;
29896 case command_FieldId_pagedir: { // bool: no argument required but value may be specified as exclude_subpages:Y
29897 *out_anon = false;
29898 } break;
29899 case command_FieldId_in: { // bool: no argument required but value may be specified as exclude_subpages:Y
29900 *out_anon = false;
29901 } break;
29902 case command_FieldId_dry_run: { // bool: no argument required but value may be specified as exclude_subpages:Y
29903 *out_anon = false;
29904 retval=0;
29905 out_dflt="Y";
29906 } break;
29907 default:
29908 retval=-1; // unrecognized
29909 }
29910 return retval;
29911}
29912
29913// --- command.wcli_proc.wcli.Start
29914// Start subprocess
29915// If subprocess already running, do nothing. Otherwise, start it
29916int command::wcli_Start(command::wcli_proc& parent) {
29917 int retval = 0;
29918 if (parent.pid == 0) {
29919 verblog(wcli_ToCmdline(parent)); // maybe print command
29920#ifdef WIN32
29921 algo_lib::ResolveExecFname(parent.path);
29922 tempstr cmdline(wcli_ToCmdline(parent));
29923 parent.pid = dospawn(Zeroterm(parent.path),Zeroterm(cmdline),parent.timeout,parent.fstdin,parent.fstdout,parent.fstderr);
29924#else
29925 parent.pid = fork();
29926 if (parent.pid == 0) { // child
29927 algo_lib::DieWithParent();
29928 if (parent.timeout > 0) {
29929 alarm(parent.timeout);
29930 }
29931 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstdin , 0);
29932 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstdout, 1);
29933 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstderr, 2);
29934 if (retval==0) retval= wcli_Execv(parent);
29935 if (retval != 0) { // if start fails, print error
29936 int err=errno;
29937 prerr("command.wcli_execv"
29938 <<Keyval("errno",err)
29939 <<Keyval("errstr",strerror(err))
29940 <<Keyval("comment","Execv failed"));
29941 }
29942 _exit(127); // if failed to start, exit anyway
29943 } else if (parent.pid == -1) {
29944 retval = errno; // failed to fork
29945 }
29946#endif
29947 }
29948 parent.status = parent.pid > 0 ? 0 : -1; // if didn't start, set error status
29949 return retval;
29950}
29951
29952// --- command.wcli_proc.wcli.StartRead
29953// Start subprocess & Read output
29954algo::Fildes command::wcli_StartRead(command::wcli_proc& parent, algo_lib::FFildes &read) {
29955 int pipefd[2];
29956 int rc=pipe(pipefd);
29957 (void)rc;
29958 read.fd.value = pipefd[0];
29959 parent.fstdout << ">&" << pipefd[1];
29960 wcli_Start(parent);
29961 (void)close(pipefd[1]);
29962 return read.fd;
29963}
29964
29965// --- command.wcli_proc.wcli.Kill
29966// Kill subprocess and wait
29967void command::wcli_Kill(command::wcli_proc& parent) {
29968 if (parent.pid != 0) {
29969 kill(parent.pid,9);
29970 wcli_Wait(parent);
29971 }
29972}
29973
29974// --- command.wcli_proc.wcli.Wait
29975// Wait for subprocess to return
29976void command::wcli_Wait(command::wcli_proc& parent) {
29977 if (parent.pid > 0) {
29978 int wait_flags = 0;
29979 int wait_status = 0;
29980 int rc = -1;
29981 do {
29982 // really wait for subprocess to exit
29983 rc = waitpid(parent.pid,&wait_status,wait_flags);
29984 } while (rc==-1 && errno==EINTR);
29985 if (rc == parent.pid) {
29986 parent.status = wait_status;
29987 parent.pid = 0;
29988 }
29989 }
29990}
29991
29992// --- command.wcli_proc.wcli.Exec
29993// Start + Wait
29994// Execute subprocess and return exit code
29995int command::wcli_Exec(command::wcli_proc& parent) {
29996 wcli_Start(parent);
29997 wcli_Wait(parent);
29998 return parent.status;
29999}
30000
30001// --- command.wcli_proc.wcli.ExecX
30002// Start + Wait, throw exception on error
30003// Execute subprocess; throw human-readable exception on error
30004void command::wcli_ExecX(command::wcli_proc& parent) {
30005 int rc = wcli_Exec(parent);
30006 vrfy(rc==0, tempstr() << "algo_lib.exec" << Keyval("cmd",wcli_ToCmdline(parent))
30007 << Keyval("comment",algo::DescribeWaitStatus(parent.status)));
30008}
30009
30010// --- command.wcli_proc.wcli.Execv
30011// Call execv()
30012// Call execv with specified parameters
30013int command::wcli_Execv(command::wcli_proc& parent) {
30014 int ret = 0;
30015 algo::StringAry args;
30016 wcli_ToArgv(parent, args);
30017 char **argv = (char**)alloca((ary_N(args)+1)*sizeof(*argv));
30018 ind_beg(algo::StringAry_ary_curs,arg,args) {
30019 argv[ind_curs(arg).index] = Zeroterm(arg);
30020 }ind_end;
30021 argv[ary_N(args)] = NULL;
30022 // if parent.path is relative, search for it in PATH
30023 algo_lib::ResolveExecFname(parent.path);
30024 ret = execv(Zeroterm(parent.path),argv);
30025 return ret;
30026}
30027
30028// --- command.wcli_proc.wcli.ToCmdline
30029algo::tempstr command::wcli_ToCmdline(command::wcli_proc& parent) {
30030 algo::tempstr retval;
30031 retval << parent.path << " ";
30032 command::wcli_PrintArgv(parent.cmd,retval);
30033 if (ch_N(parent.fstdin)) {
30034 retval << " " << parent.fstdin;
30035 }
30036 if (ch_N(parent.fstdout)) {
30037 retval << " " << parent.fstdout;
30038 }
30039 if (ch_N(parent.fstderr)) {
30040 retval << " 2" << parent.fstderr;
30041 }
30042 return retval;
30043}
30044
30045// --- command.wcli_proc.wcli.ToArgv
30046// Form array from the command line
30047void command::wcli_ToArgv(command::wcli_proc& parent, algo::StringAry& args) {
30048 ary_RemoveAll(args);
30049 ary_Alloc(args) << parent.path;
30050
30051 if (parent.cmd.selector != "issue:%") {
30052 cstring *arg = &ary_Alloc(args);
30053 *arg << "-selector:";
30054 Smallstr50_Print(parent.cmd.selector, *arg);
30055 }
30056 ind_beg(command::wcli_fields_curs,value,parent.cmd) {
30057 cstring *arg = &ary_Alloc(args);
30058 *arg << "-fields:";
30059 cstring_Print(value, *arg);
30060 }ind_end;
30061
30062 if (parent.cmd.list != false) {
30063 cstring *arg = &ary_Alloc(args);
30064 *arg << "-list:";
30065 bool_Print(parent.cmd.list, *arg);
30066 }
30067
30068 if (parent.cmd.create != false) {
30069 cstring *arg = &ary_Alloc(args);
30070 *arg << "-create:";
30071 bool_Print(parent.cmd.create, *arg);
30072 }
30073
30074 if (parent.cmd.update != false) {
30075 cstring *arg = &ary_Alloc(args);
30076 *arg << "-update:";
30077 bool_Print(parent.cmd.update, *arg);
30078 }
30079
30080 if (parent.cmd.download != false) {
30081 cstring *arg = &ary_Alloc(args);
30082 *arg << "-download:";
30083 bool_Print(parent.cmd.download, *arg);
30084 }
30085
30086 if (parent.cmd.upload != false) {
30087 cstring *arg = &ary_Alloc(args);
30088 *arg << "-upload:";
30089 bool_Print(parent.cmd.upload, *arg);
30090 }
30091
30092 if (parent.cmd.remove != false) {
30093 cstring *arg = &ary_Alloc(args);
30094 *arg << "-remove:";
30095 bool_Print(parent.cmd.remove, *arg);
30096 }
30097
30098 if (parent.cmd.t != false) {
30099 cstring *arg = &ary_Alloc(args);
30100 *arg << "-t:";
30101 bool_Print(parent.cmd.t, *arg);
30102 }
30103
30104 if (parent.cmd.e != false) {
30105 cstring *arg = &ary_Alloc(args);
30106 *arg << "-e:";
30107 bool_Print(parent.cmd.e, *arg);
30108 }
30109
30110 if (parent.cmd.ignore_saved_edit != false) {
30111 cstring *arg = &ary_Alloc(args);
30112 *arg << "-ignore_saved_edit:";
30113 bool_Print(parent.cmd.ignore_saved_edit, *arg);
30114 }
30115
30116 if (parent.cmd.exclude_subpages != false) {
30117 cstring *arg = &ary_Alloc(args);
30118 *arg << "-exclude_subpages:";
30119 bool_Print(parent.cmd.exclude_subpages, *arg);
30120 }
30121
30122 if (parent.cmd.authdir != ".ssim") {
30123 cstring *arg = &ary_Alloc(args);
30124 *arg << "-authdir:";
30125 cstring_Print(parent.cmd.authdir, *arg);
30126 }
30127
30128 if (parent.cmd.pagedir != "temp/wcli/download") {
30129 cstring *arg = &ary_Alloc(args);
30130 *arg << "-pagedir:";
30131 cstring_Print(parent.cmd.pagedir, *arg);
30132 }
30133
30134 if (parent.cmd.in != "data") {
30135 cstring *arg = &ary_Alloc(args);
30136 *arg << "-in:";
30137 cstring_Print(parent.cmd.in, *arg);
30138 }
30139
30140 if (parent.cmd.dry_run != false) {
30141 cstring *arg = &ary_Alloc(args);
30142 *arg << "-dry_run:";
30143 bool_Print(parent.cmd.dry_run, *arg);
30144 }
30145 for (int i=1; i < algo_lib::_db.cmdline.verbose; ++i) {
30146 ary_Alloc(args) << "-verbose";
30147 }
30148}
30149
30150// --- command.wcli_proc..Uninit
30151void command::wcli_proc_Uninit(command::wcli_proc& parent) {
30152 command::wcli_proc &row = parent; (void)row;
30153
30154 // command.wcli_proc.wcli.Uninit (Exec) //
30155 wcli_Kill(parent); // kill child, ensure forward progress
30156}
30157
30158// --- command.x2admin.envnode.Print
30159// Print back to string
30160void command::envnode_Print(command::x2admin& parent, algo::cstring &out) {
30161 Regx_Print(parent.envnode, out);
30162}
30163
30164// --- command.x2admin.envnode.ReadStrptrMaybe
30165// Read Regx from string
30166// Convert string to field. Return success value
30167bool command::envnode_ReadStrptrMaybe(command::x2admin& parent, algo::strptr in) {
30168 bool retval = true;
30169 Regx_ReadSql(parent.envnode, in, true);
30170 return retval;
30171}
30172
30173// --- command.x2admin.admsvc.Print
30174// Print back to string
30175void command::admsvc_Print(command::x2admin& parent, algo::cstring &out) {
30176 Regx_Print(parent.admsvc, out);
30177}
30178
30179// --- command.x2admin.admsvc.ReadStrptrMaybe
30180// Read Regx from string
30181// Convert string to field. Return success value
30182bool command::admsvc_ReadStrptrMaybe(command::x2admin& parent, algo::strptr in) {
30183 bool retval = true;
30184 Regx_ReadSql(parent.admsvc, in, true);
30185 return retval;
30186}
30187
30188// --- command.x2admin..ReadFieldMaybe
30189bool command::x2admin_ReadFieldMaybe(command::x2admin& parent, algo::strptr field, algo::strptr strval) {
30190 bool retval = true;
30191 command::FieldId field_id;
30192 (void)value_SetStrptrMaybe(field_id,field);
30193 switch(field_id) {
30194 case command_FieldId_in: {
30195 retval = algo::cstring_ReadStrptrMaybe(parent.in, strval);
30196 break;
30197 }
30198 case command_FieldId_envnode: {
30199 retval = envnode_ReadStrptrMaybe(parent, strval);
30200 break;
30201 }
30202 case command_FieldId_admsvc: {
30203 retval = admsvc_ReadStrptrMaybe(parent, strval);
30204 break;
30205 }
30206 case command_FieldId_generate: {
30207 retval = bool_ReadStrptrMaybe(parent.generate, strval);
30208 break;
30209 }
30210 case command_FieldId_update: {
30211 retval = bool_ReadStrptrMaybe(parent.update, strval);
30212 break;
30213 }
30214 case command_FieldId_verify: {
30215 retval = bool_ReadStrptrMaybe(parent.verify, strval);
30216 break;
30217 }
30218 case command_FieldId_show: {
30219 retval = bool_ReadStrptrMaybe(parent.show, strval);
30220 break;
30221 }
30222 case command_FieldId_dry_run: {
30223 retval = bool_ReadStrptrMaybe(parent.dry_run, strval);
30224 break;
30225 }
30226 default: break;
30227 }
30228 if (!retval) {
30229 algo_lib::AppendErrtext("attr",field);
30230 }
30231 return retval;
30232}
30233
30234// --- command.x2admin..ReadTupleMaybe
30235// Read fields of command::x2admin from attributes of ascii tuple TUPLE
30236bool command::x2admin_ReadTupleMaybe(command::x2admin &parent, algo::Tuple &tuple) {
30237 bool retval = true;
30238 ind_beg(algo::Tuple_attrs_curs,attr,tuple) {
30239 retval = x2admin_ReadFieldMaybe(parent, attr.name, attr.value);
30240 if (!retval) {
30241 break;
30242 }
30243 }ind_end;
30244 return retval;
30245}
30246
30247// --- command.x2admin..Init
30248// Set all fields to initial values.
30249void command::x2admin_Init(command::x2admin& parent) {
30250 parent.in = algo::strptr("data");
30251 Regx_ReadSql(parent.envnode, "%", true);
30252 Regx_ReadSql(parent.admsvc, "%", true);
30253 parent.generate = bool(false);
30254 parent.update = bool(false);
30255 parent.verify = bool(false);
30256 parent.show = bool(false);
30257 parent.dry_run = bool(false);
30258}
30259
30260// --- command.x2admin..ToCmdline
30261// Convenience function that returns a full command line
30262// Assume command is in a directory called bin
30263tempstr command::x2admin_ToCmdline(command::x2admin& row) {
30264 tempstr ret;
30265 ret << "bin/x2admin ";
30266 x2admin_PrintArgv(row, ret);
30267 // inherit less intense verbose, debug options
30268 for (int i = 1; i < algo_lib::_db.cmdline.verbose; i++) {
30269 ret << " -verbose";
30270 }
30271 for (int i = 1; i < algo_lib::_db.cmdline.debug; i++) {
30272 ret << " -debug";
30273 }
30274 return ret;
30275}
30276
30277// --- command.x2admin..PrintArgv
30278// print string representation of ROW to string STR
30279// cfmt:command.x2admin.Argv printfmt:Tuple
30280void command::x2admin_PrintArgv(command::x2admin& row, algo::cstring& str) {
30281 algo::tempstr temp;
30282 (void)temp;
30283 (void)str;
30284 if (!(row.in == "data")) {
30285 ch_RemoveAll(temp);
30286 cstring_Print(row.in, temp);
30287 str << " -in:";
30288 strptr_PrintBash(temp,str);
30289 }
30290 if (!(row.envnode.expr == "%")) {
30291 ch_RemoveAll(temp);
30292 command::envnode_Print(const_cast<command::x2admin&>(row), temp);
30293 str << " -envnode:";
30294 strptr_PrintBash(temp,str);
30295 }
30296 if (!(row.admsvc.expr == "%")) {
30297 ch_RemoveAll(temp);
30298 command::admsvc_Print(const_cast<command::x2admin&>(row), temp);
30299 str << " -admsvc:";
30300 strptr_PrintBash(temp,str);
30301 }
30302 if (!(row.generate == false)) {
30303 ch_RemoveAll(temp);
30304 bool_Print(row.generate, temp);
30305 str << " -generate:";
30306 strptr_PrintBash(temp,str);
30307 }
30308 if (!(row.update == false)) {
30309 ch_RemoveAll(temp);
30310 bool_Print(row.update, temp);
30311 str << " -update:";
30312 strptr_PrintBash(temp,str);
30313 }
30314 if (!(row.verify == false)) {
30315 ch_RemoveAll(temp);
30316 bool_Print(row.verify, temp);
30317 str << " -verify:";
30318 strptr_PrintBash(temp,str);
30319 }
30320 if (!(row.show == false)) {
30321 ch_RemoveAll(temp);
30322 bool_Print(row.show, temp);
30323 str << " -show:";
30324 strptr_PrintBash(temp,str);
30325 }
30326 if (!(row.dry_run == false)) {
30327 ch_RemoveAll(temp);
30328 bool_Print(row.dry_run, temp);
30329 str << " -dry_run:";
30330 strptr_PrintBash(temp,str);
30331 }
30332}
30333
30334// --- command.x2admin..NArgs
30335// Used with command lines
30336// Return # of command-line arguments that must follow this argument
30337// If FIELD is invalid, return -1
30338i32 command::x2admin_NArgs(command::FieldId field, algo::strptr& out_dflt, bool* out_anon) {
30339 i32 retval = 1;
30340 switch (field) {
30341 case command_FieldId_in: { // $comment
30342 *out_anon = false;
30343 } break;
30344 case command_FieldId_envnode: { // $comment
30345 *out_anon = false;
30346 } break;
30347 case command_FieldId_admsvc: { // $comment
30348 *out_anon = false;
30349 } break;
30350 case command_FieldId_generate: { // $comment
30351 *out_anon = false;
30352 retval=0;
30353 out_dflt="Y";
30354 } break;
30355 case command_FieldId_update: { // bool: no argument required but value may be specified as generate:Y
30356 *out_anon = false;
30357 retval=0;
30358 out_dflt="Y";
30359 } break;
30360 case command_FieldId_verify: { // bool: no argument required but value may be specified as update:Y
30361 *out_anon = false;
30362 retval=0;
30363 out_dflt="Y";
30364 } break;
30365 case command_FieldId_show: { // bool: no argument required but value may be specified as verify:Y
30366 *out_anon = false;
30367 retval=0;
30368 out_dflt="Y";
30369 } break;
30370 case command_FieldId_dry_run: { // bool: no argument required but value may be specified as show:Y
30371 *out_anon = false;
30372 retval=0;
30373 out_dflt="Y";
30374 } break;
30375 default:
30376 retval=-1; // unrecognized
30377 }
30378 return retval;
30379}
30380
30381// --- command.x2admin_proc.x2admin.Start
30382// Start subprocess
30383// If subprocess already running, do nothing. Otherwise, start it
30384int command::x2admin_Start(command::x2admin_proc& parent) {
30385 int retval = 0;
30386 if (parent.pid == 0) {
30387 verblog(x2admin_ToCmdline(parent)); // maybe print command
30388#ifdef WIN32
30389 algo_lib::ResolveExecFname(parent.path);
30390 tempstr cmdline(x2admin_ToCmdline(parent));
30391 parent.pid = dospawn(Zeroterm(parent.path),Zeroterm(cmdline),parent.timeout,parent.fstdin,parent.fstdout,parent.fstderr);
30392#else
30393 parent.pid = fork();
30394 if (parent.pid == 0) { // child
30395 algo_lib::DieWithParent();
30396 if (parent.timeout > 0) {
30397 alarm(parent.timeout);
30398 }
30399 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstdin , 0);
30400 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstdout, 1);
30401 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstderr, 2);
30402 if (retval==0) retval= x2admin_Execv(parent);
30403 if (retval != 0) { // if start fails, print error
30404 int err=errno;
30405 prerr("command.x2admin_execv"
30406 <<Keyval("errno",err)
30407 <<Keyval("errstr",strerror(err))
30408 <<Keyval("comment","Execv failed"));
30409 }
30410 _exit(127); // if failed to start, exit anyway
30411 } else if (parent.pid == -1) {
30412 retval = errno; // failed to fork
30413 }
30414#endif
30415 }
30416 parent.status = parent.pid > 0 ? 0 : -1; // if didn't start, set error status
30417 return retval;
30418}
30419
30420// --- command.x2admin_proc.x2admin.StartRead
30421// Start subprocess & Read output
30422algo::Fildes command::x2admin_StartRead(command::x2admin_proc& parent, algo_lib::FFildes &read) {
30423 int pipefd[2];
30424 int rc=pipe(pipefd);
30425 (void)rc;
30426 read.fd.value = pipefd[0];
30427 parent.fstdout << ">&" << pipefd[1];
30428 x2admin_Start(parent);
30429 (void)close(pipefd[1]);
30430 return read.fd;
30431}
30432
30433// --- command.x2admin_proc.x2admin.Kill
30434// Kill subprocess and wait
30435void command::x2admin_Kill(command::x2admin_proc& parent) {
30436 if (parent.pid != 0) {
30437 kill(parent.pid,9);
30438 x2admin_Wait(parent);
30439 }
30440}
30441
30442// --- command.x2admin_proc.x2admin.Wait
30443// Wait for subprocess to return
30444void command::x2admin_Wait(command::x2admin_proc& parent) {
30445 if (parent.pid > 0) {
30446 int wait_flags = 0;
30447 int wait_status = 0;
30448 int rc = -1;
30449 do {
30450 // really wait for subprocess to exit
30451 rc = waitpid(parent.pid,&wait_status,wait_flags);
30452 } while (rc==-1 && errno==EINTR);
30453 if (rc == parent.pid) {
30454 parent.status = wait_status;
30455 parent.pid = 0;
30456 }
30457 }
30458}
30459
30460// --- command.x2admin_proc.x2admin.Exec
30461// Start + Wait
30462// Execute subprocess and return exit code
30463int command::x2admin_Exec(command::x2admin_proc& parent) {
30464 x2admin_Start(parent);
30465 x2admin_Wait(parent);
30466 return parent.status;
30467}
30468
30469// --- command.x2admin_proc.x2admin.ExecX
30470// Start + Wait, throw exception on error
30471// Execute subprocess; throw human-readable exception on error
30472void command::x2admin_ExecX(command::x2admin_proc& parent) {
30473 int rc = x2admin_Exec(parent);
30474 vrfy(rc==0, tempstr() << "algo_lib.exec" << Keyval("cmd",x2admin_ToCmdline(parent))
30475 << Keyval("comment",algo::DescribeWaitStatus(parent.status)));
30476}
30477
30478// --- command.x2admin_proc.x2admin.Execv
30479// Call execv()
30480// Call execv with specified parameters
30481int command::x2admin_Execv(command::x2admin_proc& parent) {
30482 int ret = 0;
30483 algo::StringAry args;
30484 x2admin_ToArgv(parent, args);
30485 char **argv = (char**)alloca((ary_N(args)+1)*sizeof(*argv));
30486 ind_beg(algo::StringAry_ary_curs,arg,args) {
30487 argv[ind_curs(arg).index] = Zeroterm(arg);
30488 }ind_end;
30489 argv[ary_N(args)] = NULL;
30490 // if parent.path is relative, search for it in PATH
30491 algo_lib::ResolveExecFname(parent.path);
30492 ret = execv(Zeroterm(parent.path),argv);
30493 return ret;
30494}
30495
30496// --- command.x2admin_proc.x2admin.ToCmdline
30497algo::tempstr command::x2admin_ToCmdline(command::x2admin_proc& parent) {
30498 algo::tempstr retval;
30499 retval << parent.path << " ";
30500 command::x2admin_PrintArgv(parent.cmd,retval);
30501 if (ch_N(parent.fstdin)) {
30502 retval << " " << parent.fstdin;
30503 }
30504 if (ch_N(parent.fstdout)) {
30505 retval << " " << parent.fstdout;
30506 }
30507 if (ch_N(parent.fstderr)) {
30508 retval << " 2" << parent.fstderr;
30509 }
30510 return retval;
30511}
30512
30513// --- command.x2admin_proc.x2admin.ToArgv
30514// Form array from the command line
30515void command::x2admin_ToArgv(command::x2admin_proc& parent, algo::StringAry& args) {
30516 ary_RemoveAll(args);
30517 ary_Alloc(args) << parent.path;
30518
30519 if (parent.cmd.in != "data") {
30520 cstring *arg = &ary_Alloc(args);
30521 *arg << "-in:";
30522 cstring_Print(parent.cmd.in, *arg);
30523 }
30524
30525 if (parent.cmd.envnode.expr != "%") {
30526 cstring *arg = &ary_Alloc(args);
30527 *arg << "-envnode:";
30528 command::envnode_Print(parent.cmd, *arg);
30529 }
30530
30531 if (parent.cmd.admsvc.expr != "%") {
30532 cstring *arg = &ary_Alloc(args);
30533 *arg << "-admsvc:";
30534 command::admsvc_Print(parent.cmd, *arg);
30535 }
30536
30537 if (parent.cmd.generate != false) {
30538 cstring *arg = &ary_Alloc(args);
30539 *arg << "-generate:";
30540 bool_Print(parent.cmd.generate, *arg);
30541 }
30542
30543 if (parent.cmd.update != false) {
30544 cstring *arg = &ary_Alloc(args);
30545 *arg << "-update:";
30546 bool_Print(parent.cmd.update, *arg);
30547 }
30548
30549 if (parent.cmd.verify != false) {
30550 cstring *arg = &ary_Alloc(args);
30551 *arg << "-verify:";
30552 bool_Print(parent.cmd.verify, *arg);
30553 }
30554
30555 if (parent.cmd.show != false) {
30556 cstring *arg = &ary_Alloc(args);
30557 *arg << "-show:";
30558 bool_Print(parent.cmd.show, *arg);
30559 }
30560
30561 if (parent.cmd.dry_run != false) {
30562 cstring *arg = &ary_Alloc(args);
30563 *arg << "-dry_run:";
30564 bool_Print(parent.cmd.dry_run, *arg);
30565 }
30566 for (int i=1; i < algo_lib::_db.cmdline.verbose; ++i) {
30567 ary_Alloc(args) << "-verbose";
30568 }
30569}
30570
30571// --- command.x2admin_proc..Uninit
30572void command::x2admin_proc_Uninit(command::x2admin_proc& parent) {
30573 command::x2admin_proc &row = parent; (void)row;
30574
30575 // command.x2admin_proc.x2admin.Uninit (Exec) //
30576 x2admin_Kill(parent); // kill child, ensure forward progress
30577}
30578
30579// --- command.x2cmt..ReadFieldMaybe
30580bool command::x2cmt_ReadFieldMaybe(command::x2cmt& parent, algo::strptr field, algo::strptr strval) {
30581 bool retval = true;
30582 command::FieldId field_id;
30583 (void)value_SetStrptrMaybe(field_id,field);
30584 switch(field_id) {
30585 case command_FieldId_in: {
30586 retval = algo::cstring_ReadStrptrMaybe(parent.in, strval);
30587 break;
30588 }
30589 case command_FieldId_prefix: {
30590 retval = algo::cstring_ReadStrptrMaybe(parent.prefix, strval);
30591 break;
30592 }
30593 default: break;
30594 }
30595 if (!retval) {
30596 algo_lib::AppendErrtext("attr",field);
30597 }
30598 return retval;
30599}
30600
30601// --- command.x2cmt..ReadTupleMaybe
30602// Read fields of command::x2cmt from attributes of ascii tuple TUPLE
30603bool command::x2cmt_ReadTupleMaybe(command::x2cmt &parent, algo::Tuple &tuple) {
30604 bool retval = true;
30605 ind_beg(algo::Tuple_attrs_curs,attr,tuple) {
30606 retval = x2cmt_ReadFieldMaybe(parent, attr.name, attr.value);
30607 if (!retval) {
30608 break;
30609 }
30610 }ind_end;
30611 return retval;
30612}
30613
30614// --- command.x2cmt..ToCmdline
30615// Convenience function that returns a full command line
30616// Assume command is in a directory called bin
30617tempstr command::x2cmt_ToCmdline(command::x2cmt& row) {
30618 tempstr ret;
30619 ret << "bin/x2cmt ";
30620 x2cmt_PrintArgv(row, ret);
30621 // inherit less intense verbose, debug options
30622 for (int i = 1; i < algo_lib::_db.cmdline.verbose; i++) {
30623 ret << " -verbose";
30624 }
30625 for (int i = 1; i < algo_lib::_db.cmdline.debug; i++) {
30626 ret << " -debug";
30627 }
30628 return ret;
30629}
30630
30631// --- command.x2cmt..PrintArgv
30632// print string representation of ROW to string STR
30633// cfmt:command.x2cmt.Argv printfmt:Tuple
30634void command::x2cmt_PrintArgv(command::x2cmt& row, algo::cstring& str) {
30635 algo::tempstr temp;
30636 (void)temp;
30637 (void)str;
30638 if (!(row.in == "data")) {
30639 ch_RemoveAll(temp);
30640 cstring_Print(row.in, temp);
30641 str << " -in:";
30642 strptr_PrintBash(temp,str);
30643 }
30644 if (!(row.prefix == "")) {
30645 ch_RemoveAll(temp);
30646 cstring_Print(row.prefix, temp);
30647 str << " -prefix:";
30648 strptr_PrintBash(temp,str);
30649 }
30650}
30651
30652// --- command.x2cmt..NArgs
30653// Used with command lines
30654// Return # of command-line arguments that must follow this argument
30655// If FIELD is invalid, return -1
30656i32 command::x2cmt_NArgs(command::FieldId field, algo::strptr& out_dflt, bool* out_anon) {
30657 i32 retval = 1;
30658 switch (field) {
30659 case command_FieldId_in: { // $comment
30660 *out_anon = false;
30661 } break;
30662 case command_FieldId_prefix: { // $comment
30663 *out_anon = false;
30664 } break;
30665 default:
30666 retval=-1; // unrecognized
30667 }
30668 (void)out_dflt;//only to avoid -Wunused-parameter
30669 return retval;
30670}
30671
30672// --- command.x2cmt_proc.x2cmt.Start
30673// Start subprocess
30674// If subprocess already running, do nothing. Otherwise, start it
30675int command::x2cmt_Start(command::x2cmt_proc& parent) {
30676 int retval = 0;
30677 if (parent.pid == 0) {
30678 verblog(x2cmt_ToCmdline(parent)); // maybe print command
30679#ifdef WIN32
30680 algo_lib::ResolveExecFname(parent.path);
30681 tempstr cmdline(x2cmt_ToCmdline(parent));
30682 parent.pid = dospawn(Zeroterm(parent.path),Zeroterm(cmdline),parent.timeout,parent.fstdin,parent.fstdout,parent.fstderr);
30683#else
30684 parent.pid = fork();
30685 if (parent.pid == 0) { // child
30686 algo_lib::DieWithParent();
30687 if (parent.timeout > 0) {
30688 alarm(parent.timeout);
30689 }
30690 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstdin , 0);
30691 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstdout, 1);
30692 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstderr, 2);
30693 if (retval==0) retval= x2cmt_Execv(parent);
30694 if (retval != 0) { // if start fails, print error
30695 int err=errno;
30696 prerr("command.x2cmt_execv"
30697 <<Keyval("errno",err)
30698 <<Keyval("errstr",strerror(err))
30699 <<Keyval("comment","Execv failed"));
30700 }
30701 _exit(127); // if failed to start, exit anyway
30702 } else if (parent.pid == -1) {
30703 retval = errno; // failed to fork
30704 }
30705#endif
30706 }
30707 parent.status = parent.pid > 0 ? 0 : -1; // if didn't start, set error status
30708 return retval;
30709}
30710
30711// --- command.x2cmt_proc.x2cmt.StartRead
30712// Start subprocess & Read output
30713algo::Fildes command::x2cmt_StartRead(command::x2cmt_proc& parent, algo_lib::FFildes &read) {
30714 int pipefd[2];
30715 int rc=pipe(pipefd);
30716 (void)rc;
30717 read.fd.value = pipefd[0];
30718 parent.fstdout << ">&" << pipefd[1];
30719 x2cmt_Start(parent);
30720 (void)close(pipefd[1]);
30721 return read.fd;
30722}
30723
30724// --- command.x2cmt_proc.x2cmt.Kill
30725// Kill subprocess and wait
30726void command::x2cmt_Kill(command::x2cmt_proc& parent) {
30727 if (parent.pid != 0) {
30728 kill(parent.pid,9);
30729 x2cmt_Wait(parent);
30730 }
30731}
30732
30733// --- command.x2cmt_proc.x2cmt.Wait
30734// Wait for subprocess to return
30735void command::x2cmt_Wait(command::x2cmt_proc& parent) {
30736 if (parent.pid > 0) {
30737 int wait_flags = 0;
30738 int wait_status = 0;
30739 int rc = -1;
30740 do {
30741 // really wait for subprocess to exit
30742 rc = waitpid(parent.pid,&wait_status,wait_flags);
30743 } while (rc==-1 && errno==EINTR);
30744 if (rc == parent.pid) {
30745 parent.status = wait_status;
30746 parent.pid = 0;
30747 }
30748 }
30749}
30750
30751// --- command.x2cmt_proc.x2cmt.Exec
30752// Start + Wait
30753// Execute subprocess and return exit code
30754int command::x2cmt_Exec(command::x2cmt_proc& parent) {
30755 x2cmt_Start(parent);
30756 x2cmt_Wait(parent);
30757 return parent.status;
30758}
30759
30760// --- command.x2cmt_proc.x2cmt.ExecX
30761// Start + Wait, throw exception on error
30762// Execute subprocess; throw human-readable exception on error
30763void command::x2cmt_ExecX(command::x2cmt_proc& parent) {
30764 int rc = x2cmt_Exec(parent);
30765 vrfy(rc==0, tempstr() << "algo_lib.exec" << Keyval("cmd",x2cmt_ToCmdline(parent))
30766 << Keyval("comment",algo::DescribeWaitStatus(parent.status)));
30767}
30768
30769// --- command.x2cmt_proc.x2cmt.Execv
30770// Call execv()
30771// Call execv with specified parameters
30772int command::x2cmt_Execv(command::x2cmt_proc& parent) {
30773 int ret = 0;
30774 algo::StringAry args;
30775 x2cmt_ToArgv(parent, args);
30776 char **argv = (char**)alloca((ary_N(args)+1)*sizeof(*argv));
30777 ind_beg(algo::StringAry_ary_curs,arg,args) {
30778 argv[ind_curs(arg).index] = Zeroterm(arg);
30779 }ind_end;
30780 argv[ary_N(args)] = NULL;
30781 // if parent.path is relative, search for it in PATH
30782 algo_lib::ResolveExecFname(parent.path);
30783 ret = execv(Zeroterm(parent.path),argv);
30784 return ret;
30785}
30786
30787// --- command.x2cmt_proc.x2cmt.ToCmdline
30788algo::tempstr command::x2cmt_ToCmdline(command::x2cmt_proc& parent) {
30789 algo::tempstr retval;
30790 retval << parent.path << " ";
30791 command::x2cmt_PrintArgv(parent.cmd,retval);
30792 if (ch_N(parent.fstdin)) {
30793 retval << " " << parent.fstdin;
30794 }
30795 if (ch_N(parent.fstdout)) {
30796 retval << " " << parent.fstdout;
30797 }
30798 if (ch_N(parent.fstderr)) {
30799 retval << " 2" << parent.fstderr;
30800 }
30801 return retval;
30802}
30803
30804// --- command.x2cmt_proc.x2cmt.ToArgv
30805// Form array from the command line
30806void command::x2cmt_ToArgv(command::x2cmt_proc& parent, algo::StringAry& args) {
30807 ary_RemoveAll(args);
30808 ary_Alloc(args) << parent.path;
30809
30810 if (parent.cmd.in != "data") {
30811 cstring *arg = &ary_Alloc(args);
30812 *arg << "-in:";
30813 cstring_Print(parent.cmd.in, *arg);
30814 }
30815
30816 if (parent.cmd.prefix != "") {
30817 cstring *arg = &ary_Alloc(args);
30818 *arg << "-prefix:";
30819 cstring_Print(parent.cmd.prefix, *arg);
30820 }
30821 for (int i=1; i < algo_lib::_db.cmdline.verbose; ++i) {
30822 ary_Alloc(args) << "-verbose";
30823 }
30824}
30825
30826// --- command.x2cmt_proc..Uninit
30827void command::x2cmt_proc_Uninit(command::x2cmt_proc& parent) {
30828 command::x2cmt_proc &row = parent; (void)row;
30829
30830 // command.x2cmt_proc.x2cmt.Uninit (Exec) //
30831 x2cmt_Kill(parent); // kill child, ensure forward progress
30832}
30833
30834// --- command.x2gf..ReadFieldMaybe
30835bool command::x2gf_ReadFieldMaybe(command::x2gf& parent, algo::strptr field, algo::strptr strval) {
30836 bool retval = true;
30837 command::FieldId field_id;
30838 (void)value_SetStrptrMaybe(field_id,field);
30839 switch(field_id) {
30840 case command_FieldId_in: {
30841 retval = algo::cstring_ReadStrptrMaybe(parent.in, strval);
30842 break;
30843 }
30844 case command_FieldId_prefix: {
30845 retval = algo::cstring_ReadStrptrMaybe(parent.prefix, strval);
30846 break;
30847 }
30848 default: break;
30849 }
30850 if (!retval) {
30851 algo_lib::AppendErrtext("attr",field);
30852 }
30853 return retval;
30854}
30855
30856// --- command.x2gf..ReadTupleMaybe
30857// Read fields of command::x2gf from attributes of ascii tuple TUPLE
30858bool command::x2gf_ReadTupleMaybe(command::x2gf &parent, algo::Tuple &tuple) {
30859 bool retval = true;
30860 ind_beg(algo::Tuple_attrs_curs,attr,tuple) {
30861 retval = x2gf_ReadFieldMaybe(parent, attr.name, attr.value);
30862 if (!retval) {
30863 break;
30864 }
30865 }ind_end;
30866 return retval;
30867}
30868
30869// --- command.x2gf..ToCmdline
30870// Convenience function that returns a full command line
30871// Assume command is in a directory called bin
30872tempstr command::x2gf_ToCmdline(command::x2gf& row) {
30873 tempstr ret;
30874 ret << "bin/x2gf ";
30875 x2gf_PrintArgv(row, ret);
30876 // inherit less intense verbose, debug options
30877 for (int i = 1; i < algo_lib::_db.cmdline.verbose; i++) {
30878 ret << " -verbose";
30879 }
30880 for (int i = 1; i < algo_lib::_db.cmdline.debug; i++) {
30881 ret << " -debug";
30882 }
30883 return ret;
30884}
30885
30886// --- command.x2gf..PrintArgv
30887// print string representation of ROW to string STR
30888// cfmt:command.x2gf.Argv printfmt:Tuple
30889void command::x2gf_PrintArgv(command::x2gf& row, algo::cstring& str) {
30890 algo::tempstr temp;
30891 (void)temp;
30892 (void)str;
30893 if (!(row.in == "data")) {
30894 ch_RemoveAll(temp);
30895 cstring_Print(row.in, temp);
30896 str << " -in:";
30897 strptr_PrintBash(temp,str);
30898 }
30899 if (!(row.prefix == "")) {
30900 ch_RemoveAll(temp);
30901 cstring_Print(row.prefix, temp);
30902 str << " -prefix:";
30903 strptr_PrintBash(temp,str);
30904 }
30905}
30906
30907// --- command.x2gf..NArgs
30908// Used with command lines
30909// Return # of command-line arguments that must follow this argument
30910// If FIELD is invalid, return -1
30911i32 command::x2gf_NArgs(command::FieldId field, algo::strptr& out_dflt, bool* out_anon) {
30912 i32 retval = 1;
30913 switch (field) {
30914 case command_FieldId_in: { // $comment
30915 *out_anon = false;
30916 } break;
30917 case command_FieldId_prefix: { // $comment
30918 *out_anon = false;
30919 } break;
30920 default:
30921 retval=-1; // unrecognized
30922 }
30923 (void)out_dflt;//only to avoid -Wunused-parameter
30924 return retval;
30925}
30926
30927// --- command.x2gf_proc.x2gf.Start
30928// Start subprocess
30929// If subprocess already running, do nothing. Otherwise, start it
30930int command::x2gf_Start(command::x2gf_proc& parent) {
30931 int retval = 0;
30932 if (parent.pid == 0) {
30933 verblog(x2gf_ToCmdline(parent)); // maybe print command
30934#ifdef WIN32
30935 algo_lib::ResolveExecFname(parent.path);
30936 tempstr cmdline(x2gf_ToCmdline(parent));
30937 parent.pid = dospawn(Zeroterm(parent.path),Zeroterm(cmdline),parent.timeout,parent.fstdin,parent.fstdout,parent.fstderr);
30938#else
30939 parent.pid = fork();
30940 if (parent.pid == 0) { // child
30941 algo_lib::DieWithParent();
30942 if (parent.timeout > 0) {
30943 alarm(parent.timeout);
30944 }
30945 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstdin , 0);
30946 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstdout, 1);
30947 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstderr, 2);
30948 if (retval==0) retval= x2gf_Execv(parent);
30949 if (retval != 0) { // if start fails, print error
30950 int err=errno;
30951 prerr("command.x2gf_execv"
30952 <<Keyval("errno",err)
30953 <<Keyval("errstr",strerror(err))
30954 <<Keyval("comment","Execv failed"));
30955 }
30956 _exit(127); // if failed to start, exit anyway
30957 } else if (parent.pid == -1) {
30958 retval = errno; // failed to fork
30959 }
30960#endif
30961 }
30962 parent.status = parent.pid > 0 ? 0 : -1; // if didn't start, set error status
30963 return retval;
30964}
30965
30966// --- command.x2gf_proc.x2gf.StartRead
30967// Start subprocess & Read output
30968algo::Fildes command::x2gf_StartRead(command::x2gf_proc& parent, algo_lib::FFildes &read) {
30969 int pipefd[2];
30970 int rc=pipe(pipefd);
30971 (void)rc;
30972 read.fd.value = pipefd[0];
30973 parent.fstdout << ">&" << pipefd[1];
30974 x2gf_Start(parent);
30975 (void)close(pipefd[1]);
30976 return read.fd;
30977}
30978
30979// --- command.x2gf_proc.x2gf.Kill
30980// Kill subprocess and wait
30981void command::x2gf_Kill(command::x2gf_proc& parent) {
30982 if (parent.pid != 0) {
30983 kill(parent.pid,9);
30984 x2gf_Wait(parent);
30985 }
30986}
30987
30988// --- command.x2gf_proc.x2gf.Wait
30989// Wait for subprocess to return
30990void command::x2gf_Wait(command::x2gf_proc& parent) {
30991 if (parent.pid > 0) {
30992 int wait_flags = 0;
30993 int wait_status = 0;
30994 int rc = -1;
30995 do {
30996 // really wait for subprocess to exit
30997 rc = waitpid(parent.pid,&wait_status,wait_flags);
30998 } while (rc==-1 && errno==EINTR);
30999 if (rc == parent.pid) {
31000 parent.status = wait_status;
31001 parent.pid = 0;
31002 }
31003 }
31004}
31005
31006// --- command.x2gf_proc.x2gf.Exec
31007// Start + Wait
31008// Execute subprocess and return exit code
31009int command::x2gf_Exec(command::x2gf_proc& parent) {
31010 x2gf_Start(parent);
31011 x2gf_Wait(parent);
31012 return parent.status;
31013}
31014
31015// --- command.x2gf_proc.x2gf.ExecX
31016// Start + Wait, throw exception on error
31017// Execute subprocess; throw human-readable exception on error
31018void command::x2gf_ExecX(command::x2gf_proc& parent) {
31019 int rc = x2gf_Exec(parent);
31020 vrfy(rc==0, tempstr() << "algo_lib.exec" << Keyval("cmd",x2gf_ToCmdline(parent))
31021 << Keyval("comment",algo::DescribeWaitStatus(parent.status)));
31022}
31023
31024// --- command.x2gf_proc.x2gf.Execv
31025// Call execv()
31026// Call execv with specified parameters
31027int command::x2gf_Execv(command::x2gf_proc& parent) {
31028 int ret = 0;
31029 algo::StringAry args;
31030 x2gf_ToArgv(parent, args);
31031 char **argv = (char**)alloca((ary_N(args)+1)*sizeof(*argv));
31032 ind_beg(algo::StringAry_ary_curs,arg,args) {
31033 argv[ind_curs(arg).index] = Zeroterm(arg);
31034 }ind_end;
31035 argv[ary_N(args)] = NULL;
31036 // if parent.path is relative, search for it in PATH
31037 algo_lib::ResolveExecFname(parent.path);
31038 ret = execv(Zeroterm(parent.path),argv);
31039 return ret;
31040}
31041
31042// --- command.x2gf_proc.x2gf.ToCmdline
31043algo::tempstr command::x2gf_ToCmdline(command::x2gf_proc& parent) {
31044 algo::tempstr retval;
31045 retval << parent.path << " ";
31046 command::x2gf_PrintArgv(parent.cmd,retval);
31047 if (ch_N(parent.fstdin)) {
31048 retval << " " << parent.fstdin;
31049 }
31050 if (ch_N(parent.fstdout)) {
31051 retval << " " << parent.fstdout;
31052 }
31053 if (ch_N(parent.fstderr)) {
31054 retval << " 2" << parent.fstderr;
31055 }
31056 return retval;
31057}
31058
31059// --- command.x2gf_proc.x2gf.ToArgv
31060// Form array from the command line
31061void command::x2gf_ToArgv(command::x2gf_proc& parent, algo::StringAry& args) {
31062 ary_RemoveAll(args);
31063 ary_Alloc(args) << parent.path;
31064
31065 if (parent.cmd.in != "data") {
31066 cstring *arg = &ary_Alloc(args);
31067 *arg << "-in:";
31068 cstring_Print(parent.cmd.in, *arg);
31069 }
31070
31071 if (parent.cmd.prefix != "") {
31072 cstring *arg = &ary_Alloc(args);
31073 *arg << "-prefix:";
31074 cstring_Print(parent.cmd.prefix, *arg);
31075 }
31076 for (int i=1; i < algo_lib::_db.cmdline.verbose; ++i) {
31077 ary_Alloc(args) << "-verbose";
31078 }
31079}
31080
31081// --- command.x2gf_proc..Uninit
31082void command::x2gf_proc_Uninit(command::x2gf_proc& parent) {
31083 command::x2gf_proc &row = parent; (void)row;
31084
31085 // command.x2gf_proc.x2gf.Uninit (Exec) //
31086 x2gf_Kill(parent); // kill child, ensure forward progress
31087}
31088
31089// --- command.x2gw..ReadFieldMaybe
31090bool command::x2gw_ReadFieldMaybe(command::x2gw& parent, algo::strptr field, algo::strptr strval) {
31091 bool retval = true;
31092 command::FieldId field_id;
31093 (void)value_SetStrptrMaybe(field_id,field);
31094 switch(field_id) {
31095 case command_FieldId_in: {
31096 retval = algo::cstring_ReadStrptrMaybe(parent.in, strval);
31097 break;
31098 }
31099 case command_FieldId_prefix: {
31100 retval = algo::cstring_ReadStrptrMaybe(parent.prefix, strval);
31101 break;
31102 }
31103 default: break;
31104 }
31105 if (!retval) {
31106 algo_lib::AppendErrtext("attr",field);
31107 }
31108 return retval;
31109}
31110
31111// --- command.x2gw..ReadTupleMaybe
31112// Read fields of command::x2gw from attributes of ascii tuple TUPLE
31113bool command::x2gw_ReadTupleMaybe(command::x2gw &parent, algo::Tuple &tuple) {
31114 bool retval = true;
31115 ind_beg(algo::Tuple_attrs_curs,attr,tuple) {
31116 retval = x2gw_ReadFieldMaybe(parent, attr.name, attr.value);
31117 if (!retval) {
31118 break;
31119 }
31120 }ind_end;
31121 return retval;
31122}
31123
31124// --- command.x2gw..ToCmdline
31125// Convenience function that returns a full command line
31126// Assume command is in a directory called bin
31127tempstr command::x2gw_ToCmdline(command::x2gw& row) {
31128 tempstr ret;
31129 ret << "bin/x2gw ";
31130 x2gw_PrintArgv(row, ret);
31131 // inherit less intense verbose, debug options
31132 for (int i = 1; i < algo_lib::_db.cmdline.verbose; i++) {
31133 ret << " -verbose";
31134 }
31135 for (int i = 1; i < algo_lib::_db.cmdline.debug; i++) {
31136 ret << " -debug";
31137 }
31138 return ret;
31139}
31140
31141// --- command.x2gw..PrintArgv
31142// print string representation of ROW to string STR
31143// cfmt:command.x2gw.Argv printfmt:Tuple
31144void command::x2gw_PrintArgv(command::x2gw& row, algo::cstring& str) {
31145 algo::tempstr temp;
31146 (void)temp;
31147 (void)str;
31148 if (!(row.in == "data")) {
31149 ch_RemoveAll(temp);
31150 cstring_Print(row.in, temp);
31151 str << " -in:";
31152 strptr_PrintBash(temp,str);
31153 }
31154 if (!(row.prefix == "")) {
31155 ch_RemoveAll(temp);
31156 cstring_Print(row.prefix, temp);
31157 str << " -prefix:";
31158 strptr_PrintBash(temp,str);
31159 }
31160}
31161
31162// --- command.x2gw..NArgs
31163// Used with command lines
31164// Return # of command-line arguments that must follow this argument
31165// If FIELD is invalid, return -1
31166i32 command::x2gw_NArgs(command::FieldId field, algo::strptr& out_dflt, bool* out_anon) {
31167 i32 retval = 1;
31168 switch (field) {
31169 case command_FieldId_in: { // $comment
31170 *out_anon = false;
31171 } break;
31172 case command_FieldId_prefix: { // $comment
31173 *out_anon = false;
31174 } break;
31175 default:
31176 retval=-1; // unrecognized
31177 }
31178 (void)out_dflt;//only to avoid -Wunused-parameter
31179 return retval;
31180}
31181
31182// --- command.x2gw_proc.x2gw.Start
31183// Start subprocess
31184// If subprocess already running, do nothing. Otherwise, start it
31185int command::x2gw_Start(command::x2gw_proc& parent) {
31186 int retval = 0;
31187 if (parent.pid == 0) {
31188 verblog(x2gw_ToCmdline(parent)); // maybe print command
31189#ifdef WIN32
31190 algo_lib::ResolveExecFname(parent.path);
31191 tempstr cmdline(x2gw_ToCmdline(parent));
31192 parent.pid = dospawn(Zeroterm(parent.path),Zeroterm(cmdline),parent.timeout,parent.fstdin,parent.fstdout,parent.fstderr);
31193#else
31194 parent.pid = fork();
31195 if (parent.pid == 0) { // child
31196 algo_lib::DieWithParent();
31197 if (parent.timeout > 0) {
31198 alarm(parent.timeout);
31199 }
31200 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstdin , 0);
31201 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstdout, 1);
31202 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstderr, 2);
31203 if (retval==0) retval= x2gw_Execv(parent);
31204 if (retval != 0) { // if start fails, print error
31205 int err=errno;
31206 prerr("command.x2gw_execv"
31207 <<Keyval("errno",err)
31208 <<Keyval("errstr",strerror(err))
31209 <<Keyval("comment","Execv failed"));
31210 }
31211 _exit(127); // if failed to start, exit anyway
31212 } else if (parent.pid == -1) {
31213 retval = errno; // failed to fork
31214 }
31215#endif
31216 }
31217 parent.status = parent.pid > 0 ? 0 : -1; // if didn't start, set error status
31218 return retval;
31219}
31220
31221// --- command.x2gw_proc.x2gw.StartRead
31222// Start subprocess & Read output
31223algo::Fildes command::x2gw_StartRead(command::x2gw_proc& parent, algo_lib::FFildes &read) {
31224 int pipefd[2];
31225 int rc=pipe(pipefd);
31226 (void)rc;
31227 read.fd.value = pipefd[0];
31228 parent.fstdout << ">&" << pipefd[1];
31229 x2gw_Start(parent);
31230 (void)close(pipefd[1]);
31231 return read.fd;
31232}
31233
31234// --- command.x2gw_proc.x2gw.Kill
31235// Kill subprocess and wait
31236void command::x2gw_Kill(command::x2gw_proc& parent) {
31237 if (parent.pid != 0) {
31238 kill(parent.pid,9);
31239 x2gw_Wait(parent);
31240 }
31241}
31242
31243// --- command.x2gw_proc.x2gw.Wait
31244// Wait for subprocess to return
31245void command::x2gw_Wait(command::x2gw_proc& parent) {
31246 if (parent.pid > 0) {
31247 int wait_flags = 0;
31248 int wait_status = 0;
31249 int rc = -1;
31250 do {
31251 // really wait for subprocess to exit
31252 rc = waitpid(parent.pid,&wait_status,wait_flags);
31253 } while (rc==-1 && errno==EINTR);
31254 if (rc == parent.pid) {
31255 parent.status = wait_status;
31256 parent.pid = 0;
31257 }
31258 }
31259}
31260
31261// --- command.x2gw_proc.x2gw.Exec
31262// Start + Wait
31263// Execute subprocess and return exit code
31264int command::x2gw_Exec(command::x2gw_proc& parent) {
31265 x2gw_Start(parent);
31266 x2gw_Wait(parent);
31267 return parent.status;
31268}
31269
31270// --- command.x2gw_proc.x2gw.ExecX
31271// Start + Wait, throw exception on error
31272// Execute subprocess; throw human-readable exception on error
31273void command::x2gw_ExecX(command::x2gw_proc& parent) {
31274 int rc = x2gw_Exec(parent);
31275 vrfy(rc==0, tempstr() << "algo_lib.exec" << Keyval("cmd",x2gw_ToCmdline(parent))
31276 << Keyval("comment",algo::DescribeWaitStatus(parent.status)));
31277}
31278
31279// --- command.x2gw_proc.x2gw.Execv
31280// Call execv()
31281// Call execv with specified parameters
31282int command::x2gw_Execv(command::x2gw_proc& parent) {
31283 int ret = 0;
31284 algo::StringAry args;
31285 x2gw_ToArgv(parent, args);
31286 char **argv = (char**)alloca((ary_N(args)+1)*sizeof(*argv));
31287 ind_beg(algo::StringAry_ary_curs,arg,args) {
31288 argv[ind_curs(arg).index] = Zeroterm(arg);
31289 }ind_end;
31290 argv[ary_N(args)] = NULL;
31291 // if parent.path is relative, search for it in PATH
31292 algo_lib::ResolveExecFname(parent.path);
31293 ret = execv(Zeroterm(parent.path),argv);
31294 return ret;
31295}
31296
31297// --- command.x2gw_proc.x2gw.ToCmdline
31298algo::tempstr command::x2gw_ToCmdline(command::x2gw_proc& parent) {
31299 algo::tempstr retval;
31300 retval << parent.path << " ";
31301 command::x2gw_PrintArgv(parent.cmd,retval);
31302 if (ch_N(parent.fstdin)) {
31303 retval << " " << parent.fstdin;
31304 }
31305 if (ch_N(parent.fstdout)) {
31306 retval << " " << parent.fstdout;
31307 }
31308 if (ch_N(parent.fstderr)) {
31309 retval << " 2" << parent.fstderr;
31310 }
31311 return retval;
31312}
31313
31314// --- command.x2gw_proc.x2gw.ToArgv
31315// Form array from the command line
31316void command::x2gw_ToArgv(command::x2gw_proc& parent, algo::StringAry& args) {
31317 ary_RemoveAll(args);
31318 ary_Alloc(args) << parent.path;
31319
31320 if (parent.cmd.in != "data") {
31321 cstring *arg = &ary_Alloc(args);
31322 *arg << "-in:";
31323 cstring_Print(parent.cmd.in, *arg);
31324 }
31325
31326 if (parent.cmd.prefix != "") {
31327 cstring *arg = &ary_Alloc(args);
31328 *arg << "-prefix:";
31329 cstring_Print(parent.cmd.prefix, *arg);
31330 }
31331 for (int i=1; i < algo_lib::_db.cmdline.verbose; ++i) {
31332 ary_Alloc(args) << "-verbose";
31333 }
31334}
31335
31336// --- command.x2gw_proc..Uninit
31337void command::x2gw_proc_Uninit(command::x2gw_proc& parent) {
31338 command::x2gw_proc &row = parent; (void)row;
31339
31340 // command.x2gw_proc.x2gw.Uninit (Exec) //
31341 x2gw_Kill(parent); // kill child, ensure forward progress
31342}
31343
31344// --- command.x2mon..ReadFieldMaybe
31345bool command::x2mon_ReadFieldMaybe(command::x2mon& parent, algo::strptr field, algo::strptr strval) {
31346 bool retval = true;
31347 command::FieldId field_id;
31348 (void)value_SetStrptrMaybe(field_id,field);
31349 switch(field_id) {
31350 case command_FieldId_in: {
31351 retval = algo::cstring_ReadStrptrMaybe(parent.in, strval);
31352 break;
31353 }
31354 case command_FieldId_prefix: {
31355 retval = algo::cstring_ReadStrptrMaybe(parent.prefix, strval);
31356 break;
31357 }
31358 default: break;
31359 }
31360 if (!retval) {
31361 algo_lib::AppendErrtext("attr",field);
31362 }
31363 return retval;
31364}
31365
31366// --- command.x2mon..ReadTupleMaybe
31367// Read fields of command::x2mon from attributes of ascii tuple TUPLE
31368bool command::x2mon_ReadTupleMaybe(command::x2mon &parent, algo::Tuple &tuple) {
31369 bool retval = true;
31370 ind_beg(algo::Tuple_attrs_curs,attr,tuple) {
31371 retval = x2mon_ReadFieldMaybe(parent, attr.name, attr.value);
31372 if (!retval) {
31373 break;
31374 }
31375 }ind_end;
31376 return retval;
31377}
31378
31379// --- command.x2mon..ToCmdline
31380// Convenience function that returns a full command line
31381// Assume command is in a directory called bin
31382tempstr command::x2mon_ToCmdline(command::x2mon& row) {
31383 tempstr ret;
31384 ret << "bin/x2mon ";
31385 x2mon_PrintArgv(row, ret);
31386 // inherit less intense verbose, debug options
31387 for (int i = 1; i < algo_lib::_db.cmdline.verbose; i++) {
31388 ret << " -verbose";
31389 }
31390 for (int i = 1; i < algo_lib::_db.cmdline.debug; i++) {
31391 ret << " -debug";
31392 }
31393 return ret;
31394}
31395
31396// --- command.x2mon..PrintArgv
31397// print string representation of ROW to string STR
31398// cfmt:command.x2mon.Argv printfmt:Tuple
31399void command::x2mon_PrintArgv(command::x2mon& row, algo::cstring& str) {
31400 algo::tempstr temp;
31401 (void)temp;
31402 (void)str;
31403 if (!(row.in == "data")) {
31404 ch_RemoveAll(temp);
31405 cstring_Print(row.in, temp);
31406 str << " -in:";
31407 strptr_PrintBash(temp,str);
31408 }
31409 if (!(row.prefix == "")) {
31410 ch_RemoveAll(temp);
31411 cstring_Print(row.prefix, temp);
31412 str << " -prefix:";
31413 strptr_PrintBash(temp,str);
31414 }
31415}
31416
31417// --- command.x2mon..NArgs
31418// Used with command lines
31419// Return # of command-line arguments that must follow this argument
31420// If FIELD is invalid, return -1
31421i32 command::x2mon_NArgs(command::FieldId field, algo::strptr& out_dflt, bool* out_anon) {
31422 i32 retval = 1;
31423 switch (field) {
31424 case command_FieldId_in: { // $comment
31425 *out_anon = false;
31426 } break;
31427 case command_FieldId_prefix: { // $comment
31428 *out_anon = false;
31429 } break;
31430 default:
31431 retval=-1; // unrecognized
31432 }
31433 (void)out_dflt;//only to avoid -Wunused-parameter
31434 return retval;
31435}
31436
31437// --- command.x2mon_proc.x2mon.Start
31438// Start subprocess
31439// If subprocess already running, do nothing. Otherwise, start it
31440int command::x2mon_Start(command::x2mon_proc& parent) {
31441 int retval = 0;
31442 if (parent.pid == 0) {
31443 verblog(x2mon_ToCmdline(parent)); // maybe print command
31444#ifdef WIN32
31445 algo_lib::ResolveExecFname(parent.path);
31446 tempstr cmdline(x2mon_ToCmdline(parent));
31447 parent.pid = dospawn(Zeroterm(parent.path),Zeroterm(cmdline),parent.timeout,parent.fstdin,parent.fstdout,parent.fstderr);
31448#else
31449 parent.pid = fork();
31450 if (parent.pid == 0) { // child
31451 algo_lib::DieWithParent();
31452 if (parent.timeout > 0) {
31453 alarm(parent.timeout);
31454 }
31455 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstdin , 0);
31456 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstdout, 1);
31457 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstderr, 2);
31458 if (retval==0) retval= x2mon_Execv(parent);
31459 if (retval != 0) { // if start fails, print error
31460 int err=errno;
31461 prerr("command.x2mon_execv"
31462 <<Keyval("errno",err)
31463 <<Keyval("errstr",strerror(err))
31464 <<Keyval("comment","Execv failed"));
31465 }
31466 _exit(127); // if failed to start, exit anyway
31467 } else if (parent.pid == -1) {
31468 retval = errno; // failed to fork
31469 }
31470#endif
31471 }
31472 parent.status = parent.pid > 0 ? 0 : -1; // if didn't start, set error status
31473 return retval;
31474}
31475
31476// --- command.x2mon_proc.x2mon.StartRead
31477// Start subprocess & Read output
31478algo::Fildes command::x2mon_StartRead(command::x2mon_proc& parent, algo_lib::FFildes &read) {
31479 int pipefd[2];
31480 int rc=pipe(pipefd);
31481 (void)rc;
31482 read.fd.value = pipefd[0];
31483 parent.fstdout << ">&" << pipefd[1];
31484 x2mon_Start(parent);
31485 (void)close(pipefd[1]);
31486 return read.fd;
31487}
31488
31489// --- command.x2mon_proc.x2mon.Kill
31490// Kill subprocess and wait
31491void command::x2mon_Kill(command::x2mon_proc& parent) {
31492 if (parent.pid != 0) {
31493 kill(parent.pid,9);
31494 x2mon_Wait(parent);
31495 }
31496}
31497
31498// --- command.x2mon_proc.x2mon.Wait
31499// Wait for subprocess to return
31500void command::x2mon_Wait(command::x2mon_proc& parent) {
31501 if (parent.pid > 0) {
31502 int wait_flags = 0;
31503 int wait_status = 0;
31504 int rc = -1;
31505 do {
31506 // really wait for subprocess to exit
31507 rc = waitpid(parent.pid,&wait_status,wait_flags);
31508 } while (rc==-1 && errno==EINTR);
31509 if (rc == parent.pid) {
31510 parent.status = wait_status;
31511 parent.pid = 0;
31512 }
31513 }
31514}
31515
31516// --- command.x2mon_proc.x2mon.Exec
31517// Start + Wait
31518// Execute subprocess and return exit code
31519int command::x2mon_Exec(command::x2mon_proc& parent) {
31520 x2mon_Start(parent);
31521 x2mon_Wait(parent);
31522 return parent.status;
31523}
31524
31525// --- command.x2mon_proc.x2mon.ExecX
31526// Start + Wait, throw exception on error
31527// Execute subprocess; throw human-readable exception on error
31528void command::x2mon_ExecX(command::x2mon_proc& parent) {
31529 int rc = x2mon_Exec(parent);
31530 vrfy(rc==0, tempstr() << "algo_lib.exec" << Keyval("cmd",x2mon_ToCmdline(parent))
31531 << Keyval("comment",algo::DescribeWaitStatus(parent.status)));
31532}
31533
31534// --- command.x2mon_proc.x2mon.Execv
31535// Call execv()
31536// Call execv with specified parameters
31537int command::x2mon_Execv(command::x2mon_proc& parent) {
31538 int ret = 0;
31539 algo::StringAry args;
31540 x2mon_ToArgv(parent, args);
31541 char **argv = (char**)alloca((ary_N(args)+1)*sizeof(*argv));
31542 ind_beg(algo::StringAry_ary_curs,arg,args) {
31543 argv[ind_curs(arg).index] = Zeroterm(arg);
31544 }ind_end;
31545 argv[ary_N(args)] = NULL;
31546 // if parent.path is relative, search for it in PATH
31547 algo_lib::ResolveExecFname(parent.path);
31548 ret = execv(Zeroterm(parent.path),argv);
31549 return ret;
31550}
31551
31552// --- command.x2mon_proc.x2mon.ToCmdline
31553algo::tempstr command::x2mon_ToCmdline(command::x2mon_proc& parent) {
31554 algo::tempstr retval;
31555 retval << parent.path << " ";
31556 command::x2mon_PrintArgv(parent.cmd,retval);
31557 if (ch_N(parent.fstdin)) {
31558 retval << " " << parent.fstdin;
31559 }
31560 if (ch_N(parent.fstdout)) {
31561 retval << " " << parent.fstdout;
31562 }
31563 if (ch_N(parent.fstderr)) {
31564 retval << " 2" << parent.fstderr;
31565 }
31566 return retval;
31567}
31568
31569// --- command.x2mon_proc.x2mon.ToArgv
31570// Form array from the command line
31571void command::x2mon_ToArgv(command::x2mon_proc& parent, algo::StringAry& args) {
31572 ary_RemoveAll(args);
31573 ary_Alloc(args) << parent.path;
31574
31575 if (parent.cmd.in != "data") {
31576 cstring *arg = &ary_Alloc(args);
31577 *arg << "-in:";
31578 cstring_Print(parent.cmd.in, *arg);
31579 }
31580
31581 if (parent.cmd.prefix != "") {
31582 cstring *arg = &ary_Alloc(args);
31583 *arg << "-prefix:";
31584 cstring_Print(parent.cmd.prefix, *arg);
31585 }
31586 for (int i=1; i < algo_lib::_db.cmdline.verbose; ++i) {
31587 ary_Alloc(args) << "-verbose";
31588 }
31589}
31590
31591// --- command.x2mon_proc..Uninit
31592void command::x2mon_proc_Uninit(command::x2mon_proc& parent) {
31593 command::x2mon_proc &row = parent; (void)row;
31594
31595 // command.x2mon_proc.x2mon.Uninit (Exec) //
31596 x2mon_Kill(parent); // kill child, ensure forward progress
31597}
31598
31599// --- command.x2node.envnode.Print
31600// Print back to string
31601void command::envnode_Print(command::x2node& parent, algo::cstring &out) {
31602 Regx_Print(parent.envnode, out);
31603}
31604
31605// --- command.x2node.envnode.ReadStrptrMaybe
31606// Read Regx from string
31607// Convert string to field. Return success value
31608bool command::envnode_ReadStrptrMaybe(command::x2node& parent, algo::strptr in) {
31609 bool retval = true;
31610 Regx_ReadSql(parent.envnode, in, true);
31611 return retval;
31612}
31613
31614// --- command.x2node..ReadFieldMaybe
31615bool command::x2node_ReadFieldMaybe(command::x2node& parent, algo::strptr field, algo::strptr strval) {
31616 bool retval = true;
31617 command::FieldId field_id;
31618 (void)value_SetStrptrMaybe(field_id,field);
31619 switch(field_id) {
31620 case command_FieldId_in: {
31621 retval = algo::cstring_ReadStrptrMaybe(parent.in, strval);
31622 break;
31623 }
31624 case command_FieldId_envnode: {
31625 retval = envnode_ReadStrptrMaybe(parent, strval);
31626 break;
31627 }
31628 case command_FieldId_root: {
31629 retval = bool_ReadStrptrMaybe(parent.root, strval);
31630 break;
31631 }
31632 case command_FieldId_user: {
31633 retval = algo::Smallstr50_ReadStrptrMaybe(parent.user, strval);
31634 break;
31635 }
31636 case command_FieldId_shell: {
31637 retval = bool_ReadStrptrMaybe(parent.shell, strval);
31638 break;
31639 }
31640 case command_FieldId_rsync_put: {
31641 retval = bool_ReadStrptrMaybe(parent.rsync_put, strval);
31642 break;
31643 }
31644 case command_FieldId_rsync_get: {
31645 retval = bool_ReadStrptrMaybe(parent.rsync_get, strval);
31646 break;
31647 }
31648 case command_FieldId_rsync_opts: {
31649 retval = algo::cstring_ReadStrptrMaybe(parent.rsync_opts, strval);
31650 break;
31651 }
31652 case command_FieldId_local: {
31653 retval = algo::cstring_ReadStrptrMaybe(parent.local, strval);
31654 break;
31655 }
31656 case command_FieldId_remote: {
31657 retval = algo::cstring_ReadStrptrMaybe(parent.remote, strval);
31658 break;
31659 }
31660 case command_FieldId_dry_run: {
31661 retval = bool_ReadStrptrMaybe(parent.dry_run, strval);
31662 break;
31663 }
31664 case command_FieldId_maxtime: {
31665 retval = u32_ReadStrptrMaybe(parent.maxtime, strval);
31666 break;
31667 }
31668 case command_FieldId_cmd: {
31669 retval = algo::cstring_ReadStrptrMaybe(parent.cmd, strval);
31670 break;
31671 }
31672 case command_FieldId_q: {
31673 retval = bool_ReadStrptrMaybe(parent.q, strval);
31674 break;
31675 }
31676 default: break;
31677 }
31678 if (!retval) {
31679 algo_lib::AppendErrtext("attr",field);
31680 }
31681 return retval;
31682}
31683
31684// --- command.x2node..ReadTupleMaybe
31685// Read fields of command::x2node from attributes of ascii tuple TUPLE
31686bool command::x2node_ReadTupleMaybe(command::x2node &parent, algo::Tuple &tuple) {
31687 bool retval = true;
31688 int anon_idx = 0;
31689 ind_beg(algo::Tuple_attrs_curs,attr,tuple) {
31690 if (ch_N(attr.name) == 0) {
31691 attr.name = x2node_GetAnon(parent, anon_idx++);
31692 }
31693 retval = x2node_ReadFieldMaybe(parent, attr.name, attr.value);
31694 if (!retval) {
31695 break;
31696 }
31697 }ind_end;
31698 return retval;
31699}
31700
31701// --- command.x2node..Init
31702// Set all fields to initial values.
31703void command::x2node_Init(command::x2node& parent) {
31704 parent.in = algo::strptr("data");
31705 Regx_ReadSql(parent.envnode, "", true);
31706 parent.root = bool(false);
31707 parent.user = algo::strptr("");
31708 parent.shell = bool(false);
31709 parent.rsync_put = bool(false);
31710 parent.rsync_get = bool(false);
31711 parent.rsync_opts = algo::strptr("-ai");
31712 parent.local = algo::strptr("");
31713 parent.remote = algo::strptr("");
31714 parent.dry_run = bool(false);
31715 parent.maxtime = u32(0);
31716 parent.cmd = algo::strptr("");
31717 parent.q = bool(false);
31718}
31719
31720// --- command.x2node..ToCmdline
31721// Convenience function that returns a full command line
31722// Assume command is in a directory called bin
31723tempstr command::x2node_ToCmdline(command::x2node& row) {
31724 tempstr ret;
31725 ret << "bin/x2node ";
31726 x2node_PrintArgv(row, ret);
31727 // inherit less intense verbose, debug options
31728 for (int i = 1; i < algo_lib::_db.cmdline.verbose; i++) {
31729 ret << " -verbose";
31730 }
31731 for (int i = 1; i < algo_lib::_db.cmdline.debug; i++) {
31732 ret << " -debug";
31733 }
31734 return ret;
31735}
31736
31737// --- command.x2node..PrintArgv
31738// print string representation of ROW to string STR
31739// cfmt:command.x2node.Argv printfmt:Tuple
31740void command::x2node_PrintArgv(command::x2node& row, algo::cstring& str) {
31741 algo::tempstr temp;
31742 (void)temp;
31743 (void)str;
31744 if (!(row.in == "data")) {
31745 ch_RemoveAll(temp);
31746 cstring_Print(row.in, temp);
31747 str << " -in:";
31748 strptr_PrintBash(temp,str);
31749 }
31750 ch_RemoveAll(temp);
31751 command::envnode_Print(const_cast<command::x2node&>(row), temp);
31752 str << " -envnode:";
31753 strptr_PrintBash(temp,str);
31754 if (!(row.root == false)) {
31755 ch_RemoveAll(temp);
31756 bool_Print(row.root, temp);
31757 str << " -root:";
31758 strptr_PrintBash(temp,str);
31759 }
31760 if (!(row.user == "")) {
31761 ch_RemoveAll(temp);
31762 Smallstr50_Print(row.user, temp);
31763 str << " -user:";
31764 strptr_PrintBash(temp,str);
31765 }
31766 if (!(row.shell == false)) {
31767 ch_RemoveAll(temp);
31768 bool_Print(row.shell, temp);
31769 str << " -shell:";
31770 strptr_PrintBash(temp,str);
31771 }
31772 if (!(row.rsync_put == false)) {
31773 ch_RemoveAll(temp);
31774 bool_Print(row.rsync_put, temp);
31775 str << " -rsync_put:";
31776 strptr_PrintBash(temp,str);
31777 }
31778 if (!(row.rsync_get == false)) {
31779 ch_RemoveAll(temp);
31780 bool_Print(row.rsync_get, temp);
31781 str << " -rsync_get:";
31782 strptr_PrintBash(temp,str);
31783 }
31784 if (!(row.rsync_opts == "-ai")) {
31785 ch_RemoveAll(temp);
31786 cstring_Print(row.rsync_opts, temp);
31787 str << " -rsync_opts:";
31788 strptr_PrintBash(temp,str);
31789 }
31790 if (!(row.local == "")) {
31791 ch_RemoveAll(temp);
31792 cstring_Print(row.local, temp);
31793 str << " -local:";
31794 strptr_PrintBash(temp,str);
31795 }
31796 if (!(row.remote == "")) {
31797 ch_RemoveAll(temp);
31798 cstring_Print(row.remote, temp);
31799 str << " -remote:";
31800 strptr_PrintBash(temp,str);
31801 }
31802 if (!(row.dry_run == false)) {
31803 ch_RemoveAll(temp);
31804 bool_Print(row.dry_run, temp);
31805 str << " -dry_run:";
31806 strptr_PrintBash(temp,str);
31807 }
31808 if (!(row.maxtime == 0)) {
31809 ch_RemoveAll(temp);
31810 u32_Print(row.maxtime, temp);
31811 str << " -maxtime:";
31812 strptr_PrintBash(temp,str);
31813 }
31814 ch_RemoveAll(temp);
31815 cstring_Print(row.cmd, temp);
31816 str << " -cmd:";
31817 strptr_PrintBash(temp,str);
31818 if (!(row.q == false)) {
31819 ch_RemoveAll(temp);
31820 bool_Print(row.q, temp);
31821 str << " -q:";
31822 strptr_PrintBash(temp,str);
31823 }
31824}
31825
31826// --- command.x2node..GetAnon
31827algo::strptr command::x2node_GetAnon(command::x2node &parent, i32 idx) {
31828 (void)parent;//only to avoid -Wunused-parameter
31829 switch(idx) {
31830 case(0): return strptr("envnode", 7);
31831 case(1): return strptr("cmd", 3);
31832 default: return algo::strptr();
31833 }
31834}
31835
31836// --- command.x2node..NArgs
31837// Used with command lines
31838// Return # of command-line arguments that must follow this argument
31839// If FIELD is invalid, return -1
31840i32 command::x2node_NArgs(command::FieldId field, algo::strptr& out_dflt, bool* out_anon) {
31841 i32 retval = 1;
31842 switch (field) {
31843 case command_FieldId_in: { // $comment
31844 *out_anon = false;
31845 } break;
31846 case command_FieldId_envnode: { // $comment
31847 *out_anon = true;
31848 } break;
31849 case command_FieldId_root: { // $comment
31850 *out_anon = false;
31851 retval=0;
31852 out_dflt="Y";
31853 } break;
31854 case command_FieldId_user: { // bool: no argument required but value may be specified as root:Y
31855 *out_anon = false;
31856 } break;
31857 case command_FieldId_shell: { // bool: no argument required but value may be specified as root:Y
31858 *out_anon = false;
31859 retval=0;
31860 out_dflt="Y";
31861 } break;
31862 case command_FieldId_rsync_put: { // bool: no argument required but value may be specified as shell:Y
31863 *out_anon = false;
31864 retval=0;
31865 out_dflt="Y";
31866 } break;
31867 case command_FieldId_rsync_get: { // bool: no argument required but value may be specified as rsync_put:Y
31868 *out_anon = false;
31869 retval=0;
31870 out_dflt="Y";
31871 } break;
31872 case command_FieldId_rsync_opts: { // bool: no argument required but value may be specified as rsync_get:Y
31873 *out_anon = false;
31874 } break;
31875 case command_FieldId_local: { // bool: no argument required but value may be specified as rsync_get:Y
31876 *out_anon = false;
31877 } break;
31878 case command_FieldId_remote: { // bool: no argument required but value may be specified as rsync_get:Y
31879 *out_anon = false;
31880 } break;
31881 case command_FieldId_dry_run: { // bool: no argument required but value may be specified as rsync_get:Y
31882 *out_anon = false;
31883 retval=0;
31884 out_dflt="Y";
31885 } break;
31886 case command_FieldId_maxtime: { // bool: no argument required but value may be specified as dry_run:Y
31887 *out_anon = false;
31888 } break;
31889 case command_FieldId_cmd: { // bool: no argument required but value may be specified as dry_run:Y
31890 *out_anon = true;
31891 } break;
31892 case command_FieldId_q: { // bool: no argument required but value may be specified as dry_run:Y
31893 *out_anon = false;
31894 retval=0;
31895 out_dflt="Y";
31896 } break;
31897 default:
31898 retval=-1; // unrecognized
31899 }
31900 return retval;
31901}
31902
31903// --- command.x2node_proc.x2node.Start
31904// Start subprocess
31905// If subprocess already running, do nothing. Otherwise, start it
31906int command::x2node_Start(command::x2node_proc& parent) {
31907 int retval = 0;
31908 if (parent.pid == 0) {
31909 verblog(x2node_ToCmdline(parent)); // maybe print command
31910#ifdef WIN32
31911 algo_lib::ResolveExecFname(parent.path);
31912 tempstr cmdline(x2node_ToCmdline(parent));
31913 parent.pid = dospawn(Zeroterm(parent.path),Zeroterm(cmdline),parent.timeout,parent.fstdin,parent.fstdout,parent.fstderr);
31914#else
31915 parent.pid = fork();
31916 if (parent.pid == 0) { // child
31917 algo_lib::DieWithParent();
31918 if (parent.timeout > 0) {
31919 alarm(parent.timeout);
31920 }
31921 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstdin , 0);
31922 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstdout, 1);
31923 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstderr, 2);
31924 if (retval==0) retval= x2node_Execv(parent);
31925 if (retval != 0) { // if start fails, print error
31926 int err=errno;
31927 prerr("command.x2node_execv"
31928 <<Keyval("errno",err)
31929 <<Keyval("errstr",strerror(err))
31930 <<Keyval("comment","Execv failed"));
31931 }
31932 _exit(127); // if failed to start, exit anyway
31933 } else if (parent.pid == -1) {
31934 retval = errno; // failed to fork
31935 }
31936#endif
31937 }
31938 parent.status = parent.pid > 0 ? 0 : -1; // if didn't start, set error status
31939 return retval;
31940}
31941
31942// --- command.x2node_proc.x2node.StartRead
31943// Start subprocess & Read output
31944algo::Fildes command::x2node_StartRead(command::x2node_proc& parent, algo_lib::FFildes &read) {
31945 int pipefd[2];
31946 int rc=pipe(pipefd);
31947 (void)rc;
31948 read.fd.value = pipefd[0];
31949 parent.fstdout << ">&" << pipefd[1];
31950 x2node_Start(parent);
31951 (void)close(pipefd[1]);
31952 return read.fd;
31953}
31954
31955// --- command.x2node_proc.x2node.Kill
31956// Kill subprocess and wait
31957void command::x2node_Kill(command::x2node_proc& parent) {
31958 if (parent.pid != 0) {
31959 kill(parent.pid,9);
31960 x2node_Wait(parent);
31961 }
31962}
31963
31964// --- command.x2node_proc.x2node.Wait
31965// Wait for subprocess to return
31966void command::x2node_Wait(command::x2node_proc& parent) {
31967 if (parent.pid > 0) {
31968 int wait_flags = 0;
31969 int wait_status = 0;
31970 int rc = -1;
31971 do {
31972 // really wait for subprocess to exit
31973 rc = waitpid(parent.pid,&wait_status,wait_flags);
31974 } while (rc==-1 && errno==EINTR);
31975 if (rc == parent.pid) {
31976 parent.status = wait_status;
31977 parent.pid = 0;
31978 }
31979 }
31980}
31981
31982// --- command.x2node_proc.x2node.Exec
31983// Start + Wait
31984// Execute subprocess and return exit code
31985int command::x2node_Exec(command::x2node_proc& parent) {
31986 x2node_Start(parent);
31987 x2node_Wait(parent);
31988 return parent.status;
31989}
31990
31991// --- command.x2node_proc.x2node.ExecX
31992// Start + Wait, throw exception on error
31993// Execute subprocess; throw human-readable exception on error
31994void command::x2node_ExecX(command::x2node_proc& parent) {
31995 int rc = x2node_Exec(parent);
31996 vrfy(rc==0, tempstr() << "algo_lib.exec" << Keyval("cmd",x2node_ToCmdline(parent))
31997 << Keyval("comment",algo::DescribeWaitStatus(parent.status)));
31998}
31999
32000// --- command.x2node_proc.x2node.Execv
32001// Call execv()
32002// Call execv with specified parameters
32003int command::x2node_Execv(command::x2node_proc& parent) {
32004 int ret = 0;
32005 algo::StringAry args;
32006 x2node_ToArgv(parent, args);
32007 char **argv = (char**)alloca((ary_N(args)+1)*sizeof(*argv));
32008 ind_beg(algo::StringAry_ary_curs,arg,args) {
32009 argv[ind_curs(arg).index] = Zeroterm(arg);
32010 }ind_end;
32011 argv[ary_N(args)] = NULL;
32012 // if parent.path is relative, search for it in PATH
32013 algo_lib::ResolveExecFname(parent.path);
32014 ret = execv(Zeroterm(parent.path),argv);
32015 return ret;
32016}
32017
32018// --- command.x2node_proc.x2node.ToCmdline
32019algo::tempstr command::x2node_ToCmdline(command::x2node_proc& parent) {
32020 algo::tempstr retval;
32021 retval << parent.path << " ";
32022 command::x2node_PrintArgv(parent.cmd,retval);
32023 if (ch_N(parent.fstdin)) {
32024 retval << " " << parent.fstdin;
32025 }
32026 if (ch_N(parent.fstdout)) {
32027 retval << " " << parent.fstdout;
32028 }
32029 if (ch_N(parent.fstderr)) {
32030 retval << " 2" << parent.fstderr;
32031 }
32032 return retval;
32033}
32034
32035// --- command.x2node_proc.x2node.ToArgv
32036// Form array from the command line
32037void command::x2node_ToArgv(command::x2node_proc& parent, algo::StringAry& args) {
32038 ary_RemoveAll(args);
32039 ary_Alloc(args) << parent.path;
32040
32041 if (parent.cmd.in != "data") {
32042 cstring *arg = &ary_Alloc(args);
32043 *arg << "-in:";
32044 cstring_Print(parent.cmd.in, *arg);
32045 }
32046
32047 if (parent.cmd.envnode.expr != "") {
32048 cstring *arg = &ary_Alloc(args);
32049 *arg << "-envnode:";
32050 command::envnode_Print(parent.cmd, *arg);
32051 }
32052
32053 if (parent.cmd.root != false) {
32054 cstring *arg = &ary_Alloc(args);
32055 *arg << "-root:";
32056 bool_Print(parent.cmd.root, *arg);
32057 }
32058
32059 if (parent.cmd.user != "") {
32060 cstring *arg = &ary_Alloc(args);
32061 *arg << "-user:";
32062 Smallstr50_Print(parent.cmd.user, *arg);
32063 }
32064
32065 if (parent.cmd.shell != false) {
32066 cstring *arg = &ary_Alloc(args);
32067 *arg << "-shell:";
32068 bool_Print(parent.cmd.shell, *arg);
32069 }
32070
32071 if (parent.cmd.rsync_put != false) {
32072 cstring *arg = &ary_Alloc(args);
32073 *arg << "-rsync_put:";
32074 bool_Print(parent.cmd.rsync_put, *arg);
32075 }
32076
32077 if (parent.cmd.rsync_get != false) {
32078 cstring *arg = &ary_Alloc(args);
32079 *arg << "-rsync_get:";
32080 bool_Print(parent.cmd.rsync_get, *arg);
32081 }
32082
32083 if (parent.cmd.rsync_opts != "-ai") {
32084 cstring *arg = &ary_Alloc(args);
32085 *arg << "-rsync_opts:";
32086 cstring_Print(parent.cmd.rsync_opts, *arg);
32087 }
32088
32089 if (parent.cmd.local != "") {
32090 cstring *arg = &ary_Alloc(args);
32091 *arg << "-local:";
32092 cstring_Print(parent.cmd.local, *arg);
32093 }
32094
32095 if (parent.cmd.remote != "") {
32096 cstring *arg = &ary_Alloc(args);
32097 *arg << "-remote:";
32098 cstring_Print(parent.cmd.remote, *arg);
32099 }
32100
32101 if (parent.cmd.dry_run != false) {
32102 cstring *arg = &ary_Alloc(args);
32103 *arg << "-dry_run:";
32104 bool_Print(parent.cmd.dry_run, *arg);
32105 }
32106
32107 if (parent.cmd.maxtime != 0) {
32108 cstring *arg = &ary_Alloc(args);
32109 *arg << "-maxtime:";
32110 u32_Print(parent.cmd.maxtime, *arg);
32111 }
32112
32113 if (parent.cmd.cmd != "") {
32114 cstring *arg = &ary_Alloc(args);
32115 *arg << "-cmd:";
32116 cstring_Print(parent.cmd.cmd, *arg);
32117 }
32118
32119 if (parent.cmd.q != false) {
32120 cstring *arg = &ary_Alloc(args);
32121 *arg << "-q:";
32122 bool_Print(parent.cmd.q, *arg);
32123 }
32124 for (int i=1; i < algo_lib::_db.cmdline.verbose; ++i) {
32125 ary_Alloc(args) << "-verbose";
32126 }
32127}
32128
32129// --- command.x2node_proc..Uninit
32130void command::x2node_proc_Uninit(command::x2node_proc& parent) {
32131 command::x2node_proc &row = parent; (void)row;
32132
32133 // command.x2node_proc.x2node.Uninit (Exec) //
32134 x2node_Kill(parent); // kill child, ensure forward progress
32135}
32136
32137// --- command.x2read..ReadFieldMaybe
32138bool command::x2read_ReadFieldMaybe(command::x2read& parent, algo::strptr field, algo::strptr strval) {
32139 bool retval = true;
32140 command::FieldId field_id;
32141 (void)value_SetStrptrMaybe(field_id,field);
32142 switch(field_id) {
32143 case command_FieldId_in: {
32144 retval = algo::cstring_ReadStrptrMaybe(parent.in, strval);
32145 break;
32146 }
32147 case command_FieldId_gw: {
32148 retval = ietf::Ipport_ReadStrptrMaybe(parent.gw, strval);
32149 break;
32150 }
32151 default: break;
32152 }
32153 if (!retval) {
32154 algo_lib::AppendErrtext("attr",field);
32155 }
32156 return retval;
32157}
32158
32159// --- command.x2read..ReadTupleMaybe
32160// Read fields of command::x2read from attributes of ascii tuple TUPLE
32161bool command::x2read_ReadTupleMaybe(command::x2read &parent, algo::Tuple &tuple) {
32162 bool retval = true;
32163 ind_beg(algo::Tuple_attrs_curs,attr,tuple) {
32164 retval = x2read_ReadFieldMaybe(parent, attr.name, attr.value);
32165 if (!retval) {
32166 break;
32167 }
32168 }ind_end;
32169 return retval;
32170}
32171
32172// --- command.x2read..ToCmdline
32173// Convenience function that returns a full command line
32174// Assume command is in a directory called bin
32175tempstr command::x2read_ToCmdline(command::x2read& row) {
32176 tempstr ret;
32177 ret << "bin/x2read ";
32178 x2read_PrintArgv(row, ret);
32179 // inherit less intense verbose, debug options
32180 for (int i = 1; i < algo_lib::_db.cmdline.verbose; i++) {
32181 ret << " -verbose";
32182 }
32183 for (int i = 1; i < algo_lib::_db.cmdline.debug; i++) {
32184 ret << " -debug";
32185 }
32186 return ret;
32187}
32188
32189// --- command.x2read..PrintArgv
32190// print string representation of ROW to string STR
32191// cfmt:command.x2read.Argv printfmt:Tuple
32192void command::x2read_PrintArgv(command::x2read& row, algo::cstring& str) {
32193 algo::tempstr temp;
32194 (void)temp;
32195 (void)str;
32196 if (!(row.in == "data")) {
32197 ch_RemoveAll(temp);
32198 cstring_Print(row.in, temp);
32199 str << " -in:";
32200 strptr_PrintBash(temp,str);
32201 }
32202 if (!(Ipport_Eq(row.gw, ietf::Ipport()))) {
32203 ch_RemoveAll(temp);
32204 Ipport_Print(row.gw, temp);
32205 str << " -gw:";
32206 strptr_PrintBash(temp,str);
32207 }
32208}
32209
32210// --- command.x2read..NArgs
32211// Used with command lines
32212// Return # of command-line arguments that must follow this argument
32213// If FIELD is invalid, return -1
32214i32 command::x2read_NArgs(command::FieldId field, algo::strptr& out_dflt, bool* out_anon) {
32215 i32 retval = 1;
32216 switch (field) {
32217 case command_FieldId_in: { // $comment
32218 *out_anon = false;
32219 } break;
32220 case command_FieldId_gw: { // $comment
32221 *out_anon = false;
32222 } break;
32223 default:
32224 retval=-1; // unrecognized
32225 }
32226 (void)out_dflt;//only to avoid -Wunused-parameter
32227 return retval;
32228}
32229
32230// --- command.x2read_proc.x2read.Start
32231// Start subprocess
32232// If subprocess already running, do nothing. Otherwise, start it
32233int command::x2read_Start(command::x2read_proc& parent) {
32234 int retval = 0;
32235 if (parent.pid == 0) {
32236 verblog(x2read_ToCmdline(parent)); // maybe print command
32237#ifdef WIN32
32238 algo_lib::ResolveExecFname(parent.path);
32239 tempstr cmdline(x2read_ToCmdline(parent));
32240 parent.pid = dospawn(Zeroterm(parent.path),Zeroterm(cmdline),parent.timeout,parent.fstdin,parent.fstdout,parent.fstderr);
32241#else
32242 parent.pid = fork();
32243 if (parent.pid == 0) { // child
32244 algo_lib::DieWithParent();
32245 if (parent.timeout > 0) {
32246 alarm(parent.timeout);
32247 }
32248 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstdin , 0);
32249 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstdout, 1);
32250 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstderr, 2);
32251 if (retval==0) retval= x2read_Execv(parent);
32252 if (retval != 0) { // if start fails, print error
32253 int err=errno;
32254 prerr("command.x2read_execv"
32255 <<Keyval("errno",err)
32256 <<Keyval("errstr",strerror(err))
32257 <<Keyval("comment","Execv failed"));
32258 }
32259 _exit(127); // if failed to start, exit anyway
32260 } else if (parent.pid == -1) {
32261 retval = errno; // failed to fork
32262 }
32263#endif
32264 }
32265 parent.status = parent.pid > 0 ? 0 : -1; // if didn't start, set error status
32266 return retval;
32267}
32268
32269// --- command.x2read_proc.x2read.StartRead
32270// Start subprocess & Read output
32271algo::Fildes command::x2read_StartRead(command::x2read_proc& parent, algo_lib::FFildes &read) {
32272 int pipefd[2];
32273 int rc=pipe(pipefd);
32274 (void)rc;
32275 read.fd.value = pipefd[0];
32276 parent.fstdout << ">&" << pipefd[1];
32277 x2read_Start(parent);
32278 (void)close(pipefd[1]);
32279 return read.fd;
32280}
32281
32282// --- command.x2read_proc.x2read.Kill
32283// Kill subprocess and wait
32284void command::x2read_Kill(command::x2read_proc& parent) {
32285 if (parent.pid != 0) {
32286 kill(parent.pid,9);
32287 x2read_Wait(parent);
32288 }
32289}
32290
32291// --- command.x2read_proc.x2read.Wait
32292// Wait for subprocess to return
32293void command::x2read_Wait(command::x2read_proc& parent) {
32294 if (parent.pid > 0) {
32295 int wait_flags = 0;
32296 int wait_status = 0;
32297 int rc = -1;
32298 do {
32299 // really wait for subprocess to exit
32300 rc = waitpid(parent.pid,&wait_status,wait_flags);
32301 } while (rc==-1 && errno==EINTR);
32302 if (rc == parent.pid) {
32303 parent.status = wait_status;
32304 parent.pid = 0;
32305 }
32306 }
32307}
32308
32309// --- command.x2read_proc.x2read.Exec
32310// Start + Wait
32311// Execute subprocess and return exit code
32312int command::x2read_Exec(command::x2read_proc& parent) {
32313 x2read_Start(parent);
32314 x2read_Wait(parent);
32315 return parent.status;
32316}
32317
32318// --- command.x2read_proc.x2read.ExecX
32319// Start + Wait, throw exception on error
32320// Execute subprocess; throw human-readable exception on error
32321void command::x2read_ExecX(command::x2read_proc& parent) {
32322 int rc = x2read_Exec(parent);
32323 vrfy(rc==0, tempstr() << "algo_lib.exec" << Keyval("cmd",x2read_ToCmdline(parent))
32324 << Keyval("comment",algo::DescribeWaitStatus(parent.status)));
32325}
32326
32327// --- command.x2read_proc.x2read.Execv
32328// Call execv()
32329// Call execv with specified parameters
32330int command::x2read_Execv(command::x2read_proc& parent) {
32331 int ret = 0;
32332 algo::StringAry args;
32333 x2read_ToArgv(parent, args);
32334 char **argv = (char**)alloca((ary_N(args)+1)*sizeof(*argv));
32335 ind_beg(algo::StringAry_ary_curs,arg,args) {
32336 argv[ind_curs(arg).index] = Zeroterm(arg);
32337 }ind_end;
32338 argv[ary_N(args)] = NULL;
32339 // if parent.path is relative, search for it in PATH
32340 algo_lib::ResolveExecFname(parent.path);
32341 ret = execv(Zeroterm(parent.path),argv);
32342 return ret;
32343}
32344
32345// --- command.x2read_proc.x2read.ToCmdline
32346algo::tempstr command::x2read_ToCmdline(command::x2read_proc& parent) {
32347 algo::tempstr retval;
32348 retval << parent.path << " ";
32349 command::x2read_PrintArgv(parent.cmd,retval);
32350 if (ch_N(parent.fstdin)) {
32351 retval << " " << parent.fstdin;
32352 }
32353 if (ch_N(parent.fstdout)) {
32354 retval << " " << parent.fstdout;
32355 }
32356 if (ch_N(parent.fstderr)) {
32357 retval << " 2" << parent.fstderr;
32358 }
32359 return retval;
32360}
32361
32362// --- command.x2read_proc.x2read.ToArgv
32363// Form array from the command line
32364void command::x2read_ToArgv(command::x2read_proc& parent, algo::StringAry& args) {
32365 ary_RemoveAll(args);
32366 ary_Alloc(args) << parent.path;
32367
32368 if (parent.cmd.in != "data") {
32369 cstring *arg = &ary_Alloc(args);
32370 *arg << "-in:";
32371 cstring_Print(parent.cmd.in, *arg);
32372 }
32373
32374 if (true) {
32375 cstring *arg = &ary_Alloc(args);
32376 *arg << "-gw:";
32377 Ipport_Print(parent.cmd.gw, *arg);
32378 }
32379 for (int i=1; i < algo_lib::_db.cmdline.verbose; ++i) {
32380 ary_Alloc(args) << "-verbose";
32381 }
32382}
32383
32384// --- command.x2read_proc..Uninit
32385void command::x2read_proc_Uninit(command::x2read_proc& parent) {
32386 command::x2read_proc &row = parent; (void)row;
32387
32388 // command.x2read_proc.x2read.Uninit (Exec) //
32389 x2read_Kill(parent); // kill child, ensure forward progress
32390}
32391
32392// --- command.x2sup..ReadFieldMaybe
32393bool command::x2sup_ReadFieldMaybe(command::x2sup& parent, algo::strptr field, algo::strptr strval) {
32394 bool retval = true;
32395 command::FieldId field_id;
32396 (void)value_SetStrptrMaybe(field_id,field);
32397 switch(field_id) {
32398 case command_FieldId_in: {
32399 retval = algo::cstring_ReadStrptrMaybe(parent.in, strval);
32400 break;
32401 }
32402 case command_FieldId_i: {
32403 retval = bool_ReadStrptrMaybe(parent.i, strval);
32404 break;
32405 }
32406 default: break;
32407 }
32408 if (!retval) {
32409 algo_lib::AppendErrtext("attr",field);
32410 }
32411 return retval;
32412}
32413
32414// --- command.x2sup..ReadTupleMaybe
32415// Read fields of command::x2sup from attributes of ascii tuple TUPLE
32416bool command::x2sup_ReadTupleMaybe(command::x2sup &parent, algo::Tuple &tuple) {
32417 bool retval = true;
32418 ind_beg(algo::Tuple_attrs_curs,attr,tuple) {
32419 retval = x2sup_ReadFieldMaybe(parent, attr.name, attr.value);
32420 if (!retval) {
32421 break;
32422 }
32423 }ind_end;
32424 return retval;
32425}
32426
32427// --- command.x2sup..ToCmdline
32428// Convenience function that returns a full command line
32429// Assume command is in a directory called bin
32430tempstr command::x2sup_ToCmdline(command::x2sup& row) {
32431 tempstr ret;
32432 ret << "bin/x2sup ";
32433 x2sup_PrintArgv(row, ret);
32434 // inherit less intense verbose, debug options
32435 for (int i = 1; i < algo_lib::_db.cmdline.verbose; i++) {
32436 ret << " -verbose";
32437 }
32438 for (int i = 1; i < algo_lib::_db.cmdline.debug; i++) {
32439 ret << " -debug";
32440 }
32441 return ret;
32442}
32443
32444// --- command.x2sup..PrintArgv
32445// print string representation of ROW to string STR
32446// cfmt:command.x2sup.Argv printfmt:Tuple
32447void command::x2sup_PrintArgv(command::x2sup& row, algo::cstring& str) {
32448 algo::tempstr temp;
32449 (void)temp;
32450 (void)str;
32451 if (!(row.in == "data")) {
32452 ch_RemoveAll(temp);
32453 cstring_Print(row.in, temp);
32454 str << " -in:";
32455 strptr_PrintBash(temp,str);
32456 }
32457 if (!(row.i == false)) {
32458 ch_RemoveAll(temp);
32459 bool_Print(row.i, temp);
32460 str << " -i:";
32461 strptr_PrintBash(temp,str);
32462 }
32463}
32464
32465// --- command.x2sup..NArgs
32466// Used with command lines
32467// Return # of command-line arguments that must follow this argument
32468// If FIELD is invalid, return -1
32469i32 command::x2sup_NArgs(command::FieldId field, algo::strptr& out_dflt, bool* out_anon) {
32470 i32 retval = 1;
32471 switch (field) {
32472 case command_FieldId_in: { // $comment
32473 *out_anon = false;
32474 } break;
32475 case command_FieldId_i: { // $comment
32476 *out_anon = false;
32477 retval=0;
32478 out_dflt="Y";
32479 } break;
32480 default:
32481 retval=-1; // unrecognized
32482 }
32483 return retval;
32484}
32485
32486// --- command.x2sup_proc.x2sup.Start
32487// Start subprocess
32488// If subprocess already running, do nothing. Otherwise, start it
32489int command::x2sup_Start(command::x2sup_proc& parent) {
32490 int retval = 0;
32491 if (parent.pid == 0) {
32492 verblog(x2sup_ToCmdline(parent)); // maybe print command
32493#ifdef WIN32
32494 algo_lib::ResolveExecFname(parent.path);
32495 tempstr cmdline(x2sup_ToCmdline(parent));
32496 parent.pid = dospawn(Zeroterm(parent.path),Zeroterm(cmdline),parent.timeout,parent.fstdin,parent.fstdout,parent.fstderr);
32497#else
32498 parent.pid = fork();
32499 if (parent.pid == 0) { // child
32500 algo_lib::DieWithParent();
32501 if (parent.timeout > 0) {
32502 alarm(parent.timeout);
32503 }
32504 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstdin , 0);
32505 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstdout, 1);
32506 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstderr, 2);
32507 if (retval==0) retval= x2sup_Execv(parent);
32508 if (retval != 0) { // if start fails, print error
32509 int err=errno;
32510 prerr("command.x2sup_execv"
32511 <<Keyval("errno",err)
32512 <<Keyval("errstr",strerror(err))
32513 <<Keyval("comment","Execv failed"));
32514 }
32515 _exit(127); // if failed to start, exit anyway
32516 } else if (parent.pid == -1) {
32517 retval = errno; // failed to fork
32518 }
32519#endif
32520 }
32521 parent.status = parent.pid > 0 ? 0 : -1; // if didn't start, set error status
32522 return retval;
32523}
32524
32525// --- command.x2sup_proc.x2sup.StartRead
32526// Start subprocess & Read output
32527algo::Fildes command::x2sup_StartRead(command::x2sup_proc& parent, algo_lib::FFildes &read) {
32528 int pipefd[2];
32529 int rc=pipe(pipefd);
32530 (void)rc;
32531 read.fd.value = pipefd[0];
32532 parent.fstdout << ">&" << pipefd[1];
32533 x2sup_Start(parent);
32534 (void)close(pipefd[1]);
32535 return read.fd;
32536}
32537
32538// --- command.x2sup_proc.x2sup.Kill
32539// Kill subprocess and wait
32540void command::x2sup_Kill(command::x2sup_proc& parent) {
32541 if (parent.pid != 0) {
32542 kill(parent.pid,9);
32543 x2sup_Wait(parent);
32544 }
32545}
32546
32547// --- command.x2sup_proc.x2sup.Wait
32548// Wait for subprocess to return
32549void command::x2sup_Wait(command::x2sup_proc& parent) {
32550 if (parent.pid > 0) {
32551 int wait_flags = 0;
32552 int wait_status = 0;
32553 int rc = -1;
32554 do {
32555 // really wait for subprocess to exit
32556 rc = waitpid(parent.pid,&wait_status,wait_flags);
32557 } while (rc==-1 && errno==EINTR);
32558 if (rc == parent.pid) {
32559 parent.status = wait_status;
32560 parent.pid = 0;
32561 }
32562 }
32563}
32564
32565// --- command.x2sup_proc.x2sup.Exec
32566// Start + Wait
32567// Execute subprocess and return exit code
32568int command::x2sup_Exec(command::x2sup_proc& parent) {
32569 x2sup_Start(parent);
32570 x2sup_Wait(parent);
32571 return parent.status;
32572}
32573
32574// --- command.x2sup_proc.x2sup.ExecX
32575// Start + Wait, throw exception on error
32576// Execute subprocess; throw human-readable exception on error
32577void command::x2sup_ExecX(command::x2sup_proc& parent) {
32578 int rc = x2sup_Exec(parent);
32579 vrfy(rc==0, tempstr() << "algo_lib.exec" << Keyval("cmd",x2sup_ToCmdline(parent))
32580 << Keyval("comment",algo::DescribeWaitStatus(parent.status)));
32581}
32582
32583// --- command.x2sup_proc.x2sup.Execv
32584// Call execv()
32585// Call execv with specified parameters
32586int command::x2sup_Execv(command::x2sup_proc& parent) {
32587 int ret = 0;
32588 algo::StringAry args;
32589 x2sup_ToArgv(parent, args);
32590 char **argv = (char**)alloca((ary_N(args)+1)*sizeof(*argv));
32591 ind_beg(algo::StringAry_ary_curs,arg,args) {
32592 argv[ind_curs(arg).index] = Zeroterm(arg);
32593 }ind_end;
32594 argv[ary_N(args)] = NULL;
32595 // if parent.path is relative, search for it in PATH
32596 algo_lib::ResolveExecFname(parent.path);
32597 ret = execv(Zeroterm(parent.path),argv);
32598 return ret;
32599}
32600
32601// --- command.x2sup_proc.x2sup.ToCmdline
32602algo::tempstr command::x2sup_ToCmdline(command::x2sup_proc& parent) {
32603 algo::tempstr retval;
32604 retval << parent.path << " ";
32605 command::x2sup_PrintArgv(parent.cmd,retval);
32606 if (ch_N(parent.fstdin)) {
32607 retval << " " << parent.fstdin;
32608 }
32609 if (ch_N(parent.fstdout)) {
32610 retval << " " << parent.fstdout;
32611 }
32612 if (ch_N(parent.fstderr)) {
32613 retval << " 2" << parent.fstderr;
32614 }
32615 return retval;
32616}
32617
32618// --- command.x2sup_proc.x2sup.ToArgv
32619// Form array from the command line
32620void command::x2sup_ToArgv(command::x2sup_proc& parent, algo::StringAry& args) {
32621 ary_RemoveAll(args);
32622 ary_Alloc(args) << parent.path;
32623
32624 if (parent.cmd.in != "data") {
32625 cstring *arg = &ary_Alloc(args);
32626 *arg << "-in:";
32627 cstring_Print(parent.cmd.in, *arg);
32628 }
32629
32630 if (parent.cmd.i != false) {
32631 cstring *arg = &ary_Alloc(args);
32632 *arg << "-i:";
32633 bool_Print(parent.cmd.i, *arg);
32634 }
32635 for (int i=1; i < algo_lib::_db.cmdline.verbose; ++i) {
32636 ary_Alloc(args) << "-verbose";
32637 }
32638}
32639
32640// --- command.x2sup_proc..Uninit
32641void command::x2sup_proc_Uninit(command::x2sup_proc& parent) {
32642 command::x2sup_proc &row = parent; (void)row;
32643
32644 // command.x2sup_proc.x2sup.Uninit (Exec) //
32645 x2sup_Kill(parent); // kill child, ensure forward progress
32646}
32647
32648// --- command.x2txn..ReadFieldMaybe
32649bool command::x2txn_ReadFieldMaybe(command::x2txn& parent, algo::strptr field, algo::strptr strval) {
32650 bool retval = true;
32651 command::FieldId field_id;
32652 (void)value_SetStrptrMaybe(field_id,field);
32653 switch(field_id) {
32654 case command_FieldId_in: {
32655 retval = algo::cstring_ReadStrptrMaybe(parent.in, strval);
32656 break;
32657 }
32658 case command_FieldId_prefix: {
32659 retval = algo::cstring_ReadStrptrMaybe(parent.prefix, strval);
32660 break;
32661 }
32662 default: break;
32663 }
32664 if (!retval) {
32665 algo_lib::AppendErrtext("attr",field);
32666 }
32667 return retval;
32668}
32669
32670// --- command.x2txn..ReadTupleMaybe
32671// Read fields of command::x2txn from attributes of ascii tuple TUPLE
32672bool command::x2txn_ReadTupleMaybe(command::x2txn &parent, algo::Tuple &tuple) {
32673 bool retval = true;
32674 ind_beg(algo::Tuple_attrs_curs,attr,tuple) {
32675 retval = x2txn_ReadFieldMaybe(parent, attr.name, attr.value);
32676 if (!retval) {
32677 break;
32678 }
32679 }ind_end;
32680 return retval;
32681}
32682
32683// --- command.x2txn..ToCmdline
32684// Convenience function that returns a full command line
32685// Assume command is in a directory called bin
32686tempstr command::x2txn_ToCmdline(command::x2txn& row) {
32687 tempstr ret;
32688 ret << "bin/x2txn ";
32689 x2txn_PrintArgv(row, ret);
32690 // inherit less intense verbose, debug options
32691 for (int i = 1; i < algo_lib::_db.cmdline.verbose; i++) {
32692 ret << " -verbose";
32693 }
32694 for (int i = 1; i < algo_lib::_db.cmdline.debug; i++) {
32695 ret << " -debug";
32696 }
32697 return ret;
32698}
32699
32700// --- command.x2txn..PrintArgv
32701// print string representation of ROW to string STR
32702// cfmt:command.x2txn.Argv printfmt:Tuple
32703void command::x2txn_PrintArgv(command::x2txn& row, algo::cstring& str) {
32704 algo::tempstr temp;
32705 (void)temp;
32706 (void)str;
32707 if (!(row.in == "data")) {
32708 ch_RemoveAll(temp);
32709 cstring_Print(row.in, temp);
32710 str << " -in:";
32711 strptr_PrintBash(temp,str);
32712 }
32713 if (!(row.prefix == "")) {
32714 ch_RemoveAll(temp);
32715 cstring_Print(row.prefix, temp);
32716 str << " -prefix:";
32717 strptr_PrintBash(temp,str);
32718 }
32719}
32720
32721// --- command.x2txn..NArgs
32722// Used with command lines
32723// Return # of command-line arguments that must follow this argument
32724// If FIELD is invalid, return -1
32725i32 command::x2txn_NArgs(command::FieldId field, algo::strptr& out_dflt, bool* out_anon) {
32726 i32 retval = 1;
32727 switch (field) {
32728 case command_FieldId_in: { // $comment
32729 *out_anon = false;
32730 } break;
32731 case command_FieldId_prefix: { // $comment
32732 *out_anon = false;
32733 } break;
32734 default:
32735 retval=-1; // unrecognized
32736 }
32737 (void)out_dflt;//only to avoid -Wunused-parameter
32738 return retval;
32739}
32740
32741// --- command.x2txn_proc.x2txn.Start
32742// Start subprocess
32743// If subprocess already running, do nothing. Otherwise, start it
32744int command::x2txn_Start(command::x2txn_proc& parent) {
32745 int retval = 0;
32746 if (parent.pid == 0) {
32747 verblog(x2txn_ToCmdline(parent)); // maybe print command
32748#ifdef WIN32
32749 algo_lib::ResolveExecFname(parent.path);
32750 tempstr cmdline(x2txn_ToCmdline(parent));
32751 parent.pid = dospawn(Zeroterm(parent.path),Zeroterm(cmdline),parent.timeout,parent.fstdin,parent.fstdout,parent.fstderr);
32752#else
32753 parent.pid = fork();
32754 if (parent.pid == 0) { // child
32755 algo_lib::DieWithParent();
32756 if (parent.timeout > 0) {
32757 alarm(parent.timeout);
32758 }
32759 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstdin , 0);
32760 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstdout, 1);
32761 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstderr, 2);
32762 if (retval==0) retval= x2txn_Execv(parent);
32763 if (retval != 0) { // if start fails, print error
32764 int err=errno;
32765 prerr("command.x2txn_execv"
32766 <<Keyval("errno",err)
32767 <<Keyval("errstr",strerror(err))
32768 <<Keyval("comment","Execv failed"));
32769 }
32770 _exit(127); // if failed to start, exit anyway
32771 } else if (parent.pid == -1) {
32772 retval = errno; // failed to fork
32773 }
32774#endif
32775 }
32776 parent.status = parent.pid > 0 ? 0 : -1; // if didn't start, set error status
32777 return retval;
32778}
32779
32780// --- command.x2txn_proc.x2txn.StartRead
32781// Start subprocess & Read output
32782algo::Fildes command::x2txn_StartRead(command::x2txn_proc& parent, algo_lib::FFildes &read) {
32783 int pipefd[2];
32784 int rc=pipe(pipefd);
32785 (void)rc;
32786 read.fd.value = pipefd[0];
32787 parent.fstdout << ">&" << pipefd[1];
32788 x2txn_Start(parent);
32789 (void)close(pipefd[1]);
32790 return read.fd;
32791}
32792
32793// --- command.x2txn_proc.x2txn.Kill
32794// Kill subprocess and wait
32795void command::x2txn_Kill(command::x2txn_proc& parent) {
32796 if (parent.pid != 0) {
32797 kill(parent.pid,9);
32798 x2txn_Wait(parent);
32799 }
32800}
32801
32802// --- command.x2txn_proc.x2txn.Wait
32803// Wait for subprocess to return
32804void command::x2txn_Wait(command::x2txn_proc& parent) {
32805 if (parent.pid > 0) {
32806 int wait_flags = 0;
32807 int wait_status = 0;
32808 int rc = -1;
32809 do {
32810 // really wait for subprocess to exit
32811 rc = waitpid(parent.pid,&wait_status,wait_flags);
32812 } while (rc==-1 && errno==EINTR);
32813 if (rc == parent.pid) {
32814 parent.status = wait_status;
32815 parent.pid = 0;
32816 }
32817 }
32818}
32819
32820// --- command.x2txn_proc.x2txn.Exec
32821// Start + Wait
32822// Execute subprocess and return exit code
32823int command::x2txn_Exec(command::x2txn_proc& parent) {
32824 x2txn_Start(parent);
32825 x2txn_Wait(parent);
32826 return parent.status;
32827}
32828
32829// --- command.x2txn_proc.x2txn.ExecX
32830// Start + Wait, throw exception on error
32831// Execute subprocess; throw human-readable exception on error
32832void command::x2txn_ExecX(command::x2txn_proc& parent) {
32833 int rc = x2txn_Exec(parent);
32834 vrfy(rc==0, tempstr() << "algo_lib.exec" << Keyval("cmd",x2txn_ToCmdline(parent))
32835 << Keyval("comment",algo::DescribeWaitStatus(parent.status)));
32836}
32837
32838// --- command.x2txn_proc.x2txn.Execv
32839// Call execv()
32840// Call execv with specified parameters
32841int command::x2txn_Execv(command::x2txn_proc& parent) {
32842 int ret = 0;
32843 algo::StringAry args;
32844 x2txn_ToArgv(parent, args);
32845 char **argv = (char**)alloca((ary_N(args)+1)*sizeof(*argv));
32846 ind_beg(algo::StringAry_ary_curs,arg,args) {
32847 argv[ind_curs(arg).index] = Zeroterm(arg);
32848 }ind_end;
32849 argv[ary_N(args)] = NULL;
32850 // if parent.path is relative, search for it in PATH
32851 algo_lib::ResolveExecFname(parent.path);
32852 ret = execv(Zeroterm(parent.path),argv);
32853 return ret;
32854}
32855
32856// --- command.x2txn_proc.x2txn.ToCmdline
32857algo::tempstr command::x2txn_ToCmdline(command::x2txn_proc& parent) {
32858 algo::tempstr retval;
32859 retval << parent.path << " ";
32860 command::x2txn_PrintArgv(parent.cmd,retval);
32861 if (ch_N(parent.fstdin)) {
32862 retval << " " << parent.fstdin;
32863 }
32864 if (ch_N(parent.fstdout)) {
32865 retval << " " << parent.fstdout;
32866 }
32867 if (ch_N(parent.fstderr)) {
32868 retval << " 2" << parent.fstderr;
32869 }
32870 return retval;
32871}
32872
32873// --- command.x2txn_proc.x2txn.ToArgv
32874// Form array from the command line
32875void command::x2txn_ToArgv(command::x2txn_proc& parent, algo::StringAry& args) {
32876 ary_RemoveAll(args);
32877 ary_Alloc(args) << parent.path;
32878
32879 if (parent.cmd.in != "data") {
32880 cstring *arg = &ary_Alloc(args);
32881 *arg << "-in:";
32882 cstring_Print(parent.cmd.in, *arg);
32883 }
32884
32885 if (parent.cmd.prefix != "") {
32886 cstring *arg = &ary_Alloc(args);
32887 *arg << "-prefix:";
32888 cstring_Print(parent.cmd.prefix, *arg);
32889 }
32890 for (int i=1; i < algo_lib::_db.cmdline.verbose; ++i) {
32891 ary_Alloc(args) << "-verbose";
32892 }
32893}
32894
32895// --- command.x2txn_proc..Uninit
32896void command::x2txn_proc_Uninit(command::x2txn_proc& parent) {
32897 command::x2txn_proc &row = parent; (void)row;
32898
32899 // command.x2txn_proc.x2txn.Uninit (Exec) //
32900 x2txn_Kill(parent); // kill child, ensure forward progress
32901}
32902
32903// --- command.x2write..ReadFieldMaybe
32904bool command::x2write_ReadFieldMaybe(command::x2write& parent, algo::strptr field, algo::strptr strval) {
32905 bool retval = true;
32906 command::FieldId field_id;
32907 (void)value_SetStrptrMaybe(field_id,field);
32908 switch(field_id) {
32909 case command_FieldId_in: {
32910 retval = algo::cstring_ReadStrptrMaybe(parent.in, strval);
32911 break;
32912 }
32913 case command_FieldId_gw: {
32914 retval = ietf::Ipport_ReadStrptrMaybe(parent.gw, strval);
32915 break;
32916 }
32917 default: break;
32918 }
32919 if (!retval) {
32920 algo_lib::AppendErrtext("attr",field);
32921 }
32922 return retval;
32923}
32924
32925// --- command.x2write..ReadTupleMaybe
32926// Read fields of command::x2write from attributes of ascii tuple TUPLE
32927bool command::x2write_ReadTupleMaybe(command::x2write &parent, algo::Tuple &tuple) {
32928 bool retval = true;
32929 ind_beg(algo::Tuple_attrs_curs,attr,tuple) {
32930 retval = x2write_ReadFieldMaybe(parent, attr.name, attr.value);
32931 if (!retval) {
32932 break;
32933 }
32934 }ind_end;
32935 return retval;
32936}
32937
32938// --- command.x2write..ToCmdline
32939// Convenience function that returns a full command line
32940// Assume command is in a directory called bin
32941tempstr command::x2write_ToCmdline(command::x2write& row) {
32942 tempstr ret;
32943 ret << "bin/x2write ";
32944 x2write_PrintArgv(row, ret);
32945 // inherit less intense verbose, debug options
32946 for (int i = 1; i < algo_lib::_db.cmdline.verbose; i++) {
32947 ret << " -verbose";
32948 }
32949 for (int i = 1; i < algo_lib::_db.cmdline.debug; i++) {
32950 ret << " -debug";
32951 }
32952 return ret;
32953}
32954
32955// --- command.x2write..PrintArgv
32956// print string representation of ROW to string STR
32957// cfmt:command.x2write.Argv printfmt:Tuple
32958void command::x2write_PrintArgv(command::x2write& row, algo::cstring& str) {
32959 algo::tempstr temp;
32960 (void)temp;
32961 (void)str;
32962 if (!(row.in == "data")) {
32963 ch_RemoveAll(temp);
32964 cstring_Print(row.in, temp);
32965 str << " -in:";
32966 strptr_PrintBash(temp,str);
32967 }
32968 if (!(Ipport_Eq(row.gw, ietf::Ipport()))) {
32969 ch_RemoveAll(temp);
32970 Ipport_Print(row.gw, temp);
32971 str << " -gw:";
32972 strptr_PrintBash(temp,str);
32973 }
32974}
32975
32976// --- command.x2write..NArgs
32977// Used with command lines
32978// Return # of command-line arguments that must follow this argument
32979// If FIELD is invalid, return -1
32980i32 command::x2write_NArgs(command::FieldId field, algo::strptr& out_dflt, bool* out_anon) {
32981 i32 retval = 1;
32982 switch (field) {
32983 case command_FieldId_in: { // $comment
32984 *out_anon = false;
32985 } break;
32986 case command_FieldId_gw: { // $comment
32987 *out_anon = false;
32988 } break;
32989 default:
32990 retval=-1; // unrecognized
32991 }
32992 (void)out_dflt;//only to avoid -Wunused-parameter
32993 return retval;
32994}
32995
32996// --- command.x2write_proc.x2write.Start
32997// Start subprocess
32998// If subprocess already running, do nothing. Otherwise, start it
32999int command::x2write_Start(command::x2write_proc& parent) {
33000 int retval = 0;
33001 if (parent.pid == 0) {
33002 verblog(x2write_ToCmdline(parent)); // maybe print command
33003#ifdef WIN32
33004 algo_lib::ResolveExecFname(parent.path);
33005 tempstr cmdline(x2write_ToCmdline(parent));
33006 parent.pid = dospawn(Zeroterm(parent.path),Zeroterm(cmdline),parent.timeout,parent.fstdin,parent.fstdout,parent.fstderr);
33007#else
33008 parent.pid = fork();
33009 if (parent.pid == 0) { // child
33010 algo_lib::DieWithParent();
33011 if (parent.timeout > 0) {
33012 alarm(parent.timeout);
33013 }
33014 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstdin , 0);
33015 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstdout, 1);
33016 if (retval==0) retval=algo_lib::ApplyRedirect(parent.fstderr, 2);
33017 if (retval==0) retval= x2write_Execv(parent);
33018 if (retval != 0) { // if start fails, print error
33019 int err=errno;
33020 prerr("command.x2write_execv"
33021 <<Keyval("errno",err)
33022 <<Keyval("errstr",strerror(err))
33023 <<Keyval("comment","Execv failed"));
33024 }
33025 _exit(127); // if failed to start, exit anyway
33026 } else if (parent.pid == -1) {
33027 retval = errno; // failed to fork
33028 }
33029#endif
33030 }
33031 parent.status = parent.pid > 0 ? 0 : -1; // if didn't start, set error status
33032 return retval;
33033}
33034
33035// --- command.x2write_proc.x2write.StartRead
33036// Start subprocess & Read output
33037algo::Fildes command::x2write_StartRead(command::x2write_proc& parent, algo_lib::FFildes &read) {
33038 int pipefd[2];
33039 int rc=pipe(pipefd);
33040 (void)rc;
33041 read.fd.value = pipefd[0];
33042 parent.fstdout << ">&" << pipefd[1];
33043 x2write_Start(parent);
33044 (void)close(pipefd[1]);
33045 return read.fd;
33046}
33047
33048// --- command.x2write_proc.x2write.Kill
33049// Kill subprocess and wait
33050void command::x2write_Kill(command::x2write_proc& parent) {
33051 if (parent.pid != 0) {
33052 kill(parent.pid,9);
33053 x2write_Wait(parent);
33054 }
33055}
33056
33057// --- command.x2write_proc.x2write.Wait
33058// Wait for subprocess to return
33059void command::x2write_Wait(command::x2write_proc& parent) {
33060 if (parent.pid > 0) {
33061 int wait_flags = 0;
33062 int wait_status = 0;
33063 int rc = -1;
33064 do {
33065 // really wait for subprocess to exit
33066 rc = waitpid(parent.pid,&wait_status,wait_flags);
33067 } while (rc==-1 && errno==EINTR);
33068 if (rc == parent.pid) {
33069 parent.status = wait_status;
33070 parent.pid = 0;
33071 }
33072 }
33073}
33074
33075// --- command.x2write_proc.x2write.Exec
33076// Start + Wait
33077// Execute subprocess and return exit code
33078int command::x2write_Exec(command::x2write_proc& parent) {
33079 x2write_Start(parent);
33080 x2write_Wait(parent);
33081 return parent.status;
33082}
33083
33084// --- command.x2write_proc.x2write.ExecX
33085// Start + Wait, throw exception on error
33086// Execute subprocess; throw human-readable exception on error
33087void command::x2write_ExecX(command::x2write_proc& parent) {
33088 int rc = x2write_Exec(parent);
33089 vrfy(rc==0, tempstr() << "algo_lib.exec" << Keyval("cmd",x2write_ToCmdline(parent))
33090 << Keyval("comment",algo::DescribeWaitStatus(parent.status)));
33091}
33092
33093// --- command.x2write_proc.x2write.Execv
33094// Call execv()
33095// Call execv with specified parameters
33096int command::x2write_Execv(command::x2write_proc& parent) {
33097 int ret = 0;
33098 algo::StringAry args;
33099 x2write_ToArgv(parent, args);
33100 char **argv = (char**)alloca((ary_N(args)+1)*sizeof(*argv));
33101 ind_beg(algo::StringAry_ary_curs,arg,args) {
33102 argv[ind_curs(arg).index] = Zeroterm(arg);
33103 }ind_end;
33104 argv[ary_N(args)] = NULL;
33105 // if parent.path is relative, search for it in PATH
33106 algo_lib::ResolveExecFname(parent.path);
33107 ret = execv(Zeroterm(parent.path),argv);
33108 return ret;
33109}
33110
33111// --- command.x2write_proc.x2write.ToCmdline
33112algo::tempstr command::x2write_ToCmdline(command::x2write_proc& parent) {
33113 algo::tempstr retval;
33114 retval << parent.path << " ";
33115 command::x2write_PrintArgv(parent.cmd,retval);
33116 if (ch_N(parent.fstdin)) {
33117 retval << " " << parent.fstdin;
33118 }
33119 if (ch_N(parent.fstdout)) {
33120 retval << " " << parent.fstdout;
33121 }
33122 if (ch_N(parent.fstderr)) {
33123 retval << " 2" << parent.fstderr;
33124 }
33125 return retval;
33126}
33127
33128// --- command.x2write_proc.x2write.ToArgv
33129// Form array from the command line
33130void command::x2write_ToArgv(command::x2write_proc& parent, algo::StringAry& args) {
33131 ary_RemoveAll(args);
33132 ary_Alloc(args) << parent.path;
33133
33134 if (parent.cmd.in != "data") {
33135 cstring *arg = &ary_Alloc(args);
33136 *arg << "-in:";
33137 cstring_Print(parent.cmd.in, *arg);
33138 }
33139
33140 if (true) {
33141 cstring *arg = &ary_Alloc(args);
33142 *arg << "-gw:";
33143 Ipport_Print(parent.cmd.gw, *arg);
33144 }
33145 for (int i=1; i < algo_lib::_db.cmdline.verbose; ++i) {
33146 ary_Alloc(args) << "-verbose";
33147 }
33148}
33149
33150// --- command.x2write_proc..Uninit
33151void command::x2write_proc_Uninit(command::x2write_proc& parent) {
33152 command::x2write_proc &row = parent; (void)row;
33153
33154 // command.x2write_proc.x2write.Uninit (Exec) //
33155 x2write_Kill(parent); // kill child, ensure forward progress
33156}
33157
33158// --- command...SizeCheck
33159inline static void command::SizeCheck() {
33160}
33161
33162// --- command...StaticCheck
33163void command::StaticCheck() {
33164 algo_assert(_offset_of(command::FieldId, value) + sizeof(((command::FieldId*)0)->value) == sizeof(command::FieldId));
33165}